├── .github └── workflows │ └── ci.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── cipher_suite.go ├── go.mod ├── go.sum ├── hkdf.go ├── noise_test.go ├── patterns.go ├── state.go ├── vector_test.go ├── vectorgen └── vectorgen.go └── vectors.txt /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | name: CI 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Install Go 8 | uses: actions/setup-go@v2 9 | with: 10 | go-version: 1.16.x 11 | - name: Checkout code 12 | uses: actions/checkout@v2 13 | - name: Test 14 | run: go test ./... 15 | lint: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: golangci-lint 20 | uses: golangci/golangci-lint-action@v2 21 | with: 22 | version: latest 23 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | See the [Flynn contributing guide](https://flynn.io/docs/contributing). 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Flynn® is a trademark of Prime Directive, Inc. 2 | 3 | Copyright (c) 2015 Prime Directive, Inc. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following disclaimer 13 | in the documentation and/or other materials provided with the 14 | distribution. 15 | * Neither the name of Prime Directive, Inc. nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # noise [![Go Reference](https://pkg.go.dev/badge/github.com/flynn/noise.svg)](https://pkg.go.dev/github.com/flynn/noise) [![CI Status](https://github.com/flynn/noise/actions/workflows/ci.yml/badge.svg)](https://github.com/flynn/noise/actions) 2 | 3 | This is a Go package that implements the [Noise Protocol 4 | Framework](https://noiseprotocol.org). See [the 5 | documentation](https://pkg.go.dev/github.com/flynn/noise) for usage information. 6 | -------------------------------------------------------------------------------- /cipher_suite.go: -------------------------------------------------------------------------------- 1 | package noise 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "crypto/rand" 7 | "crypto/sha256" 8 | "crypto/sha512" 9 | "encoding/binary" 10 | "hash" 11 | "io" 12 | 13 | "golang.org/x/crypto/blake2b" 14 | "golang.org/x/crypto/blake2s" 15 | "golang.org/x/crypto/chacha20poly1305" 16 | "golang.org/x/crypto/curve25519" 17 | ) 18 | 19 | // A DHKey is a keypair used for Diffie-Hellman key agreement. 20 | type DHKey struct { 21 | Private []byte 22 | Public []byte 23 | } 24 | 25 | // A DHFunc implements Diffie-Hellman key agreement. 26 | type DHFunc interface { 27 | // GenerateKeypair generates a new keypair using random as a source of 28 | // entropy. 29 | GenerateKeypair(random io.Reader) (DHKey, error) 30 | 31 | // DH performs a Diffie-Hellman calculation between the provided private and 32 | // public keys and returns the result. 33 | DH(privkey, pubkey []byte) ([]byte, error) 34 | 35 | // DHLen is the number of bytes returned by DH. 36 | DHLen() int 37 | 38 | // DHName is the name of the DH function. 39 | DHName() string 40 | } 41 | 42 | // A HashFunc implements a cryptographic hash function. 43 | type HashFunc interface { 44 | // Hash returns a hash state. 45 | Hash() hash.Hash 46 | 47 | // HashName is the name of the hash function. 48 | HashName() string 49 | } 50 | 51 | // A CipherFunc implements an AEAD symmetric cipher. 52 | type CipherFunc interface { 53 | // Cipher initializes the algorithm with the provided key and returns a Cipher. 54 | Cipher(k [32]byte) Cipher 55 | 56 | // CipherName is the name of the cipher. 57 | CipherName() string 58 | } 59 | 60 | // A Cipher is a AEAD cipher that has been initialized with a key. 61 | type Cipher interface { 62 | // Encrypt encrypts the provided plaintext with a nonce and then appends the 63 | // ciphertext to out along with an authentication tag over the ciphertext 64 | // and optional authenticated data. 65 | Encrypt(out []byte, n uint64, ad, plaintext []byte) []byte 66 | 67 | // Decrypt authenticates the ciphertext and optional authenticated data and 68 | // then decrypts the provided ciphertext using the provided nonce and 69 | // appends it to out. 70 | Decrypt(out []byte, n uint64, ad, ciphertext []byte) ([]byte, error) 71 | } 72 | 73 | // A CipherSuite is a set of cryptographic primitives used in a Noise protocol. 74 | // It should be constructed with NewCipherSuite. 75 | type CipherSuite interface { 76 | DHFunc 77 | CipherFunc 78 | HashFunc 79 | Name() []byte 80 | } 81 | 82 | // NewCipherSuite returns a CipherSuite constructed from the specified 83 | // primitives. 84 | func NewCipherSuite(dh DHFunc, c CipherFunc, h HashFunc) CipherSuite { 85 | return ciphersuite{ 86 | DHFunc: dh, 87 | CipherFunc: c, 88 | HashFunc: h, 89 | name: []byte(dh.DHName() + "_" + c.CipherName() + "_" + h.HashName()), 90 | } 91 | } 92 | 93 | type ciphersuite struct { 94 | DHFunc 95 | CipherFunc 96 | HashFunc 97 | name []byte 98 | } 99 | 100 | func (s ciphersuite) Name() []byte { return s.name } 101 | 102 | // DH25519 is the Curve25519 ECDH function. 103 | var DH25519 DHFunc = dh25519{} 104 | 105 | type dh25519 struct{} 106 | 107 | func (dh25519) GenerateKeypair(rng io.Reader) (DHKey, error) { 108 | privkey := make([]byte, 32) 109 | if rng == nil { 110 | rng = rand.Reader 111 | } 112 | if _, err := io.ReadFull(rng, privkey); err != nil { 113 | return DHKey{}, err 114 | } 115 | pubkey, err := curve25519.X25519(privkey, curve25519.Basepoint) 116 | if err != nil { 117 | return DHKey{}, err 118 | } 119 | return DHKey{Private: privkey, Public: pubkey}, nil 120 | } 121 | 122 | func (dh25519) DH(privkey, pubkey []byte) ([]byte, error) { 123 | return curve25519.X25519(privkey, pubkey) 124 | } 125 | 126 | func (dh25519) DHLen() int { return 32 } 127 | func (dh25519) DHName() string { return "25519" } 128 | 129 | type cipherFn struct { 130 | fn func([32]byte) Cipher 131 | name string 132 | } 133 | 134 | func (c cipherFn) Cipher(k [32]byte) Cipher { return c.fn(k) } 135 | func (c cipherFn) CipherName() string { return c.name } 136 | 137 | // CipherAESGCM is the AES256-GCM AEAD cipher. 138 | var CipherAESGCM CipherFunc = cipherFn{cipherAESGCM, "AESGCM"} 139 | 140 | func cipherAESGCM(k [32]byte) Cipher { 141 | c, err := aes.NewCipher(k[:]) 142 | if err != nil { 143 | panic(err) 144 | } 145 | gcm, err := cipher.NewGCM(c) 146 | if err != nil { 147 | panic(err) 148 | } 149 | return aeadCipher{ 150 | gcm, 151 | func(n uint64) []byte { 152 | var nonce [12]byte 153 | binary.BigEndian.PutUint64(nonce[4:], n) 154 | return nonce[:] 155 | }, 156 | } 157 | } 158 | 159 | // CipherChaChaPoly is the ChaCha20-Poly1305 AEAD cipher construction. 160 | var CipherChaChaPoly CipherFunc = cipherFn{cipherChaChaPoly, "ChaChaPoly"} 161 | 162 | func cipherChaChaPoly(k [32]byte) Cipher { 163 | c, err := chacha20poly1305.New(k[:]) 164 | if err != nil { 165 | panic(err) 166 | } 167 | return aeadCipher{ 168 | c, 169 | func(n uint64) []byte { 170 | var nonce [12]byte 171 | binary.LittleEndian.PutUint64(nonce[4:], n) 172 | return nonce[:] 173 | }, 174 | } 175 | } 176 | 177 | type aeadCipher struct { 178 | cipher.AEAD 179 | nonce func(uint64) []byte 180 | } 181 | 182 | func (c aeadCipher) Encrypt(out []byte, n uint64, ad, plaintext []byte) []byte { 183 | return c.Seal(out, c.nonce(n), plaintext, ad) 184 | } 185 | 186 | func (c aeadCipher) Decrypt(out []byte, n uint64, ad, ciphertext []byte) ([]byte, error) { 187 | return c.Open(out, c.nonce(n), ciphertext, ad) 188 | } 189 | 190 | type hashFn struct { 191 | fn func() hash.Hash 192 | name string 193 | } 194 | 195 | func (h hashFn) Hash() hash.Hash { return h.fn() } 196 | func (h hashFn) HashName() string { return h.name } 197 | 198 | // HashSHA256 is the SHA-256 hash function. 199 | var HashSHA256 HashFunc = hashFn{sha256.New, "SHA256"} 200 | 201 | // HashSHA512 is the SHA-512 hash function. 202 | var HashSHA512 HashFunc = hashFn{sha512.New, "SHA512"} 203 | 204 | func blake2bNew() hash.Hash { 205 | h, err := blake2b.New512(nil) 206 | if err != nil { 207 | panic(err) 208 | } 209 | return h 210 | } 211 | 212 | // HashBLAKE2b is the BLAKE2b hash function. 213 | var HashBLAKE2b HashFunc = hashFn{blake2bNew, "BLAKE2b"} 214 | 215 | func blake2sNew() hash.Hash { 216 | h, err := blake2s.New256(nil) 217 | if err != nil { 218 | panic(err) 219 | } 220 | return h 221 | } 222 | 223 | // HashBLAKE2s is the BLAKE2s hash function. 224 | var HashBLAKE2s HashFunc = hashFn{blake2sNew, "BLAKE2s"} 225 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/flynn/noise 2 | 3 | go 1.16 4 | 5 | require ( 6 | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 7 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 2 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 3 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 4 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 5 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 6 | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= 7 | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 8 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 9 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= 10 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 11 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 12 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 13 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 14 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 15 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 16 | -------------------------------------------------------------------------------- /hkdf.go: -------------------------------------------------------------------------------- 1 | package noise 2 | 3 | import ( 4 | "crypto/hmac" 5 | "hash" 6 | ) 7 | 8 | func hkdf(h func() hash.Hash, outputs int, out1, out2, out3, chainingKey, inputKeyMaterial []byte) ([]byte, []byte, []byte) { 9 | if len(out1) > 0 { 10 | panic("len(out1) > 0") 11 | } 12 | if len(out2) > 0 { 13 | panic("len(out2) > 0") 14 | } 15 | if len(out3) > 0 { 16 | panic("len(out3) > 0") 17 | } 18 | if outputs > 3 { 19 | panic("outputs > 3") 20 | } 21 | 22 | tempMAC := hmac.New(h, chainingKey) 23 | tempMAC.Write(inputKeyMaterial) 24 | tempKey := tempMAC.Sum(out2) 25 | 26 | out1MAC := hmac.New(h, tempKey) 27 | out1MAC.Write([]byte{0x01}) 28 | out1 = out1MAC.Sum(out1) 29 | 30 | if outputs == 1 { 31 | return out1, nil, nil 32 | } 33 | 34 | out2MAC := hmac.New(h, tempKey) 35 | out2MAC.Write(out1) 36 | out2MAC.Write([]byte{0x02}) 37 | out2 = out2MAC.Sum(out2) 38 | 39 | if outputs == 2 { 40 | return out1, out2, nil 41 | } 42 | 43 | out3MAC := hmac.New(h, tempKey) 44 | out3MAC.Write(out2) 45 | out3MAC.Write([]byte{0x03}) 46 | out3 = out3MAC.Sum(out3) 47 | 48 | return out1, out2, out3 49 | } 50 | -------------------------------------------------------------------------------- /noise_test.go: -------------------------------------------------------------------------------- 1 | package noise 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "math" 7 | "testing" 8 | 9 | . "gopkg.in/check.v1" 10 | ) 11 | 12 | func Test(t *testing.T) { TestingT(t) } 13 | 14 | type NoiseSuite struct{} 15 | 16 | var _ = Suite(&NoiseSuite{}) 17 | 18 | type RandomInc byte 19 | 20 | func (r *RandomInc) Read(p []byte) (int, error) { 21 | for i := range p { 22 | p[i] = byte(*r) 23 | *r = (*r) + 1 24 | } 25 | return len(p), nil 26 | } 27 | 28 | func (NoiseSuite) TestN(c *C) { 29 | cs := NewCipherSuite(DH25519, CipherAESGCM, HashSHA256) 30 | rng := new(RandomInc) 31 | staticR, _ := cs.GenerateKeypair(rng) 32 | hs, _ := NewHandshakeState(Config{ 33 | CipherSuite: cs, 34 | Random: rng, 35 | Pattern: HandshakeN, 36 | Initiator: true, 37 | PeerStatic: staticR.Public, 38 | }) 39 | 40 | hello, _, _, _ := hs.WriteMessage(nil, nil) 41 | expected, _ := hex.DecodeString("358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd1662548331a3d1e93b490263abc7a4633867f4") 42 | c.Assert(hello, DeepEquals, expected) 43 | } 44 | 45 | func (NoiseSuite) TestX(c *C) { 46 | cs := NewCipherSuite(DH25519, CipherChaChaPoly, HashSHA256) 47 | rng := new(RandomInc) 48 | staticI, _ := cs.GenerateKeypair(rng) 49 | staticR, _ := cs.GenerateKeypair(rng) 50 | hs, _ := NewHandshakeState(Config{ 51 | CipherSuite: cs, 52 | Random: rng, 53 | Pattern: HandshakeX, 54 | Initiator: true, 55 | StaticKeypair: staticI, 56 | PeerStatic: staticR.Public, 57 | }) 58 | 59 | hello, _, _, _ := hs.WriteMessage(nil, nil) 60 | expected, _ := hex.DecodeString("79a631eede1bf9c98f12032cdeadd0e7a079398fc786b88cc846ec89af85a51ad203cd28d81cf65a2da637f557a05728b3ae4abdc3a42d1cda5f719d6cf41d7f2cf1b1c5af10e38a09a9bb7e3b1d589a99492cc50293eaa1f3f391b59bb6990d") 61 | c.Assert(hello, DeepEquals, expected) 62 | } 63 | 64 | func (NoiseSuite) TestNN(c *C) { 65 | cs := NewCipherSuite(DH25519, CipherAESGCM, HashSHA512) 66 | rngI := new(RandomInc) 67 | rngR := new(RandomInc) 68 | *rngR = 1 69 | 70 | hsI, _ := NewHandshakeState(Config{ 71 | CipherSuite: cs, 72 | Random: rngI, 73 | Pattern: HandshakeNN, 74 | Initiator: true, 75 | }) 76 | hsR, _ := NewHandshakeState(Config{ 77 | CipherSuite: cs, 78 | Random: rngR, 79 | Pattern: HandshakeNN, 80 | Initiator: false, 81 | }) 82 | 83 | msg, _, _, _ := hsI.WriteMessage(nil, []byte("abc")) 84 | c.Assert(msg, HasLen, 35) 85 | res, _, _, err := hsR.ReadMessage(nil, msg) 86 | c.Assert(err, IsNil) 87 | c.Assert(string(res), Equals, "abc") 88 | 89 | msg, _, _, _ = hsR.WriteMessage(nil, []byte("defg")) 90 | c.Assert(msg, HasLen, 52) 91 | res, _, _, err = hsI.ReadMessage(nil, msg) 92 | c.Assert(err, IsNil) 93 | c.Assert(string(res), Equals, "defg") 94 | 95 | expected, _ := hex.DecodeString("07a37cbc142093c8b755dc1b10e86cb426374ad16aa853ed0bdfc0b2b86d1c7c5e4dc9545d41b3280f4586a5481829e1e24ec5a0") 96 | c.Assert(msg, DeepEquals, expected) 97 | } 98 | 99 | func (NoiseSuite) TestXX(c *C) { 100 | cs := NewCipherSuite(DH25519, CipherAESGCM, HashSHA256) 101 | rngI := new(RandomInc) 102 | rngR := new(RandomInc) 103 | *rngR = 1 104 | 105 | staticI, _ := cs.GenerateKeypair(rngI) 106 | staticR, _ := cs.GenerateKeypair(rngR) 107 | 108 | hsI, _ := NewHandshakeState(Config{ 109 | CipherSuite: cs, 110 | Random: rngI, 111 | Pattern: HandshakeXX, 112 | Initiator: true, 113 | StaticKeypair: staticI, 114 | }) 115 | hsR, _ := NewHandshakeState(Config{ 116 | CipherSuite: cs, 117 | Random: rngR, 118 | Pattern: HandshakeXX, 119 | StaticKeypair: staticR, 120 | }) 121 | 122 | msg, _, _, _ := hsI.WriteMessage(nil, []byte("abc")) 123 | c.Assert(msg, HasLen, 35) 124 | res, _, _, err := hsR.ReadMessage(nil, msg) 125 | c.Assert(err, IsNil) 126 | c.Assert(string(res), Equals, "abc") 127 | 128 | msg, _, _, _ = hsR.WriteMessage(nil, []byte("defg")) 129 | c.Assert(msg, HasLen, 100) 130 | res, _, _, err = hsI.ReadMessage(nil, msg) 131 | c.Assert(err, IsNil) 132 | c.Assert(string(res), Equals, "defg") 133 | 134 | msg, _, _, _ = hsI.WriteMessage(nil, nil) 135 | c.Assert(msg, HasLen, 64) 136 | res, _, _, err = hsR.ReadMessage(nil, msg) 137 | c.Assert(err, IsNil) 138 | c.Assert(res, HasLen, 0) 139 | 140 | expected, _ := hex.DecodeString("8127f4b35cdbdf0935fcf1ec99016d1dcbc350055b8af360be196905dfb50a2c1c38a7ca9cb0cfe8f4576f36c47a4933eee32288f590ac4305d4b53187577be7") 141 | c.Assert(msg, DeepEquals, expected) 142 | } 143 | 144 | func (NoiseSuite) TestIK(c *C) { 145 | cs := NewCipherSuite(DH25519, CipherAESGCM, HashSHA256) 146 | rngI := new(RandomInc) 147 | rngR := new(RandomInc) 148 | *rngR = 1 149 | 150 | staticI, _ := cs.GenerateKeypair(rngI) 151 | staticR, _ := cs.GenerateKeypair(rngR) 152 | 153 | hsI, _ := NewHandshakeState(Config{ 154 | CipherSuite: cs, 155 | Random: rngI, 156 | Pattern: HandshakeIK, 157 | Initiator: true, 158 | Prologue: []byte("ABC"), 159 | StaticKeypair: staticI, 160 | PeerStatic: staticR.Public, 161 | }) 162 | hsR, _ := NewHandshakeState(Config{ 163 | CipherSuite: cs, 164 | Random: rngR, 165 | Pattern: HandshakeIK, 166 | Prologue: []byte("ABC"), 167 | StaticKeypair: staticR, 168 | }) 169 | 170 | msg, _, _, _ := hsI.WriteMessage(nil, []byte("abc")) 171 | c.Assert(msg, HasLen, 99) 172 | res, _, _, err := hsR.ReadMessage(nil, msg) 173 | c.Assert(err, IsNil) 174 | c.Assert(string(res), Equals, "abc") 175 | 176 | msg, _, _, _ = hsR.WriteMessage(nil, []byte("defg")) 177 | c.Assert(msg, HasLen, 52) 178 | res, _, _, err = hsI.ReadMessage(nil, msg) 179 | c.Assert(err, IsNil) 180 | c.Assert(string(res), Equals, "defg") 181 | 182 | expected, _ := hex.DecodeString("5869aff450549732cbaaed5e5df9b30a6da31cb0e5742bad5ad4a1a768f1a67b7555a94199d0ce2972e0861b06c2152419a278de") 183 | c.Assert(msg, DeepEquals, expected) 184 | } 185 | 186 | func (NoiseSuite) TestXXRoundtrip(c *C) { 187 | cs := NewCipherSuite(DH25519, CipherAESGCM, HashSHA256) 188 | rngI := new(RandomInc) 189 | rngR := new(RandomInc) 190 | *rngR = 1 191 | 192 | staticI, _ := cs.GenerateKeypair(rngI) 193 | staticR, _ := cs.GenerateKeypair(rngR) 194 | 195 | hsI, _ := NewHandshakeState(Config{ 196 | CipherSuite: cs, 197 | Random: rngI, 198 | Pattern: HandshakeXX, 199 | Initiator: true, 200 | StaticKeypair: staticI, 201 | }) 202 | hsR, _ := NewHandshakeState(Config{ 203 | CipherSuite: cs, 204 | Random: rngR, 205 | Pattern: HandshakeXX, 206 | StaticKeypair: staticR, 207 | }) 208 | 209 | // -> e 210 | msg, _, _, _ := hsI.WriteMessage(nil, []byte("abcdef")) 211 | c.Assert(msg, HasLen, 38) 212 | res, _, _, err := hsR.ReadMessage(nil, msg) 213 | c.Assert(err, IsNil) 214 | c.Assert(string(res), Equals, "abcdef") 215 | 216 | // <- e, dhee, s, dhse 217 | msg, _, _, _ = hsR.WriteMessage(nil, nil) 218 | c.Assert(msg, HasLen, 96) 219 | res, _, _, err = hsI.ReadMessage(nil, msg) 220 | c.Assert(err, IsNil) 221 | c.Assert(res, HasLen, 0) 222 | 223 | // -> s, dhse 224 | payload := "0123456789012345678901234567890123456789012345678901234567890123456789" 225 | msg, csI0, csI1, _ := hsI.WriteMessage(nil, []byte(payload)) 226 | c.Assert(msg, HasLen, 134) 227 | res, csR0, csR1, err := hsR.ReadMessage(nil, msg) 228 | c.Assert(err, IsNil) 229 | c.Assert(string(res), Equals, payload) 230 | 231 | // transport message I -> R 232 | msg, err = csI0.Encrypt(nil, nil, []byte("wubba")) 233 | c.Assert(err, IsNil) 234 | res, err = csR0.Decrypt(nil, nil, msg) 235 | c.Assert(err, IsNil) 236 | c.Assert(string(res), Equals, "wubba") 237 | 238 | // transport message I -> R again 239 | msg, err = csI0.Encrypt(nil, nil, []byte("aleph")) 240 | c.Assert(err, IsNil) 241 | res, err = csR0.Decrypt(nil, nil, msg) 242 | c.Assert(err, IsNil) 243 | c.Assert(string(res), Equals, "aleph") 244 | 245 | // transport message R <- I 246 | msg, err = csR1.Encrypt(nil, nil, []byte("worri")) 247 | c.Assert(err, IsNil) 248 | res, err = csI1.Decrypt(nil, nil, msg) 249 | c.Assert(err, IsNil) 250 | c.Assert(string(res), Equals, "worri") 251 | } 252 | 253 | func (NoiseSuite) Test_IXpsk2_Roundtrip(c *C) { 254 | cs := NewCipherSuite(DH25519, CipherAESGCM, HashSHA256) 255 | rngI := new(RandomInc) 256 | rngR := new(RandomInc) 257 | *rngR = 1 258 | 259 | staticI, err := cs.GenerateKeypair(rngI) 260 | if err != nil { 261 | c.Fatal(err) 262 | } 263 | staticR, err := cs.GenerateKeypair(rngR) 264 | if err != nil { 265 | c.Fatal(err) 266 | } 267 | 268 | psk := []byte("00000000000000000000000000000000") 269 | 270 | hsI, _ := NewHandshakeState(Config{ 271 | CipherSuite: cs, 272 | Random: rngI, 273 | Pattern: HandshakeIX, 274 | PresharedKeyPlacement: 2, 275 | PresharedKey: psk, 276 | Initiator: true, 277 | StaticKeypair: staticI, 278 | }) 279 | hsR, _ := NewHandshakeState(Config{ 280 | CipherSuite: cs, 281 | Random: rngR, 282 | Pattern: HandshakeIX, 283 | PresharedKeyPlacement: 2, 284 | StaticKeypair: staticR, 285 | }) 286 | 287 | // -> e, s 288 | msg, _, _, _ := hsI.WriteMessage(nil, nil) 289 | c.Assert(msg, HasLen, 96) 290 | 291 | res, _, _, err := hsR.ReadMessage(nil, msg) 292 | c.Assert(err, IsNil) 293 | c.Assert(res, HasLen, 0) 294 | 295 | if !bytes.Equal(hsR.PeerStatic(), staticI.Public) { 296 | c.Error("wrong public key from peer") 297 | } 298 | 299 | // Look up psk from peer static public key 300 | 301 | // responder should know psk now and set it from the 302 | // initiators preshared key 303 | if err = hsR.SetPresharedKey(psk); err != nil { 304 | c.Fatal(err) 305 | } 306 | // <- e, dhee, dhse, s, dhes, psk 307 | msg, csR0, csR1, _ := hsR.WriteMessage(nil, nil) 308 | c.Assert(msg, HasLen, 96) 309 | res, csI0, csI1, err := hsI.ReadMessage(nil, msg) 310 | c.Assert(err, IsNil) 311 | c.Assert(res, HasLen, 0) 312 | 313 | // transport I -> R 314 | msg, err = csI0.Encrypt(nil, nil, []byte("foo")) 315 | c.Assert(err, IsNil) 316 | res, err = csR0.Decrypt(nil, nil, msg) 317 | c.Assert(err, IsNil) 318 | c.Assert(string(res), Equals, "foo") 319 | 320 | // transport R -> I 321 | msg, err = csR1.Encrypt(nil, nil, []byte("bar")) 322 | c.Assert(err, IsNil) 323 | res, err = csI1.Decrypt(nil, nil, msg) 324 | c.Assert(err, IsNil) 325 | c.Assert(string(res), Equals, "bar") 326 | } 327 | 328 | func (NoiseSuite) Test_NNpsk0_Roundtrip(c *C) { 329 | cs := NewCipherSuite(DH25519, CipherChaChaPoly, HashBLAKE2b) 330 | rngI := new(RandomInc) 331 | rngR := new(RandomInc) 332 | *rngR = 1 333 | 334 | hsI, _ := NewHandshakeState(Config{ 335 | CipherSuite: cs, 336 | Random: rngI, 337 | Pattern: HandshakeNN, 338 | Initiator: true, 339 | PresharedKey: []byte("supersecretsupersecretsupersecre"), 340 | }) 341 | hsR, _ := NewHandshakeState(Config{ 342 | CipherSuite: cs, 343 | Random: rngR, 344 | Pattern: HandshakeNN, 345 | PresharedKey: []byte("supersecretsupersecretsupersecre"), 346 | }) 347 | 348 | // -> e 349 | msg, _, _, _ := hsI.WriteMessage(nil, nil) 350 | c.Assert(msg, HasLen, 48) 351 | res, _, _, err := hsR.ReadMessage(nil, msg) 352 | c.Assert(err, IsNil) 353 | c.Assert(res, HasLen, 0) 354 | 355 | // <- e, dhee 356 | msg, csR0, csR1, _ := hsR.WriteMessage(nil, nil) 357 | c.Assert(msg, HasLen, 48) 358 | res, csI0, csI1, err := hsI.ReadMessage(nil, msg) 359 | c.Assert(err, IsNil) 360 | c.Assert(res, HasLen, 0) 361 | 362 | // transport I -> R 363 | msg, err = csI0.Encrypt(nil, nil, []byte("foo")) 364 | c.Assert(err, IsNil) 365 | res, err = csR0.Decrypt(nil, nil, msg) 366 | c.Assert(err, IsNil) 367 | c.Assert(string(res), Equals, "foo") 368 | 369 | // transport R -> I 370 | msg, err = csR1.Encrypt(nil, nil, []byte("bar")) 371 | c.Assert(err, IsNil) 372 | res, err = csI1.Decrypt(nil, nil, msg) 373 | c.Assert(err, IsNil) 374 | c.Assert(string(res), Equals, "bar") 375 | } 376 | 377 | func (NoiseSuite) Test_Npsk0(c *C) { 378 | cs := NewCipherSuite(DH25519, CipherAESGCM, HashSHA256) 379 | rng := new(RandomInc) 380 | staticR, _ := cs.GenerateKeypair(rng) 381 | 382 | hsI, _ := NewHandshakeState(Config{ 383 | CipherSuite: cs, 384 | Random: rng, 385 | Pattern: HandshakeN, 386 | Initiator: true, 387 | PresharedKey: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20}, 388 | PeerStatic: staticR.Public, 389 | }) 390 | 391 | msg, _, _, _ := hsI.WriteMessage(nil, nil) 392 | c.Assert(msg, HasLen, 48) 393 | 394 | expected, _ := hex.DecodeString("358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd1662542044ae563929068930dcf04674526cb9") 395 | c.Assert(msg, DeepEquals, expected) 396 | } 397 | 398 | func (NoiseSuite) Test_Xpsk0(c *C) { 399 | cs := NewCipherSuite(DH25519, CipherChaChaPoly, HashSHA256) 400 | rng := new(RandomInc) 401 | staticI, _ := cs.GenerateKeypair(rng) 402 | staticR, _ := cs.GenerateKeypair(rng) 403 | 404 | hs, _ := NewHandshakeState(Config{ 405 | CipherSuite: cs, 406 | Random: rng, 407 | Pattern: HandshakeX, 408 | Initiator: true, 409 | PresharedKey: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20}, 410 | StaticKeypair: staticI, 411 | PeerStatic: staticR.Public, 412 | }) 413 | msg, _, _, _ := hs.WriteMessage(nil, nil) 414 | c.Assert(msg, HasLen, 96) 415 | 416 | expected, _ := hex.DecodeString("79a631eede1bf9c98f12032cdeadd0e7a079398fc786b88cc846ec89af85a51ad51eef529db0dd9127d4aa59a9183e118337d75a4e55e7e00f85c3d20ede536dd0112eec8c3b2a514018a90ab685b027dd24aa0c70b0c0f00524cc23785028b9") 417 | c.Assert(msg, DeepEquals, expected) 418 | } 419 | 420 | func (NoiseSuite) Test_NNpsk0(c *C) { 421 | cs := NewCipherSuite(DH25519, CipherAESGCM, HashSHA512) 422 | rngI := new(RandomInc) 423 | rngR := new(RandomInc) 424 | *rngR = 1 425 | prologue := []byte{0x01, 0x02, 0x03} 426 | psk := []byte{0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23} 427 | 428 | hsI, _ := NewHandshakeState(Config{ 429 | CipherSuite: cs, 430 | Random: rngI, 431 | Pattern: HandshakeNN, 432 | Initiator: true, 433 | Prologue: prologue, 434 | PresharedKey: psk, 435 | }) 436 | hsR, _ := NewHandshakeState(Config{ 437 | CipherSuite: cs, 438 | Random: rngR, 439 | Pattern: HandshakeNN, 440 | Prologue: prologue, 441 | PresharedKey: psk, 442 | }) 443 | 444 | msg, _, _, _ := hsI.WriteMessage(nil, []byte("abc")) 445 | c.Assert(msg, HasLen, 51) 446 | res, _, _, err := hsR.ReadMessage(nil, msg) 447 | c.Assert(err, IsNil) 448 | c.Assert(string(res), Equals, "abc") 449 | 450 | msg, _, _, _ = hsR.WriteMessage(nil, []byte("defg")) 451 | c.Assert(msg, HasLen, 52) 452 | res, _, _, err = hsI.ReadMessage(nil, msg) 453 | c.Assert(err, IsNil) 454 | c.Assert(string(res), Equals, "defg") 455 | 456 | expected, _ := hex.DecodeString("07a37cbc142093c8b755dc1b10e86cb426374ad16aa853ed0bdfc0b2b86d1c7c3e42e140cfffbcdf5d9d2a1c24ce4cdbdf1eaf37") 457 | c.Assert(msg, DeepEquals, expected) 458 | } 459 | 460 | func (NoiseSuite) Test_XXpsk0(c *C) { 461 | cs := NewCipherSuite(DH25519, CipherAESGCM, HashSHA256) 462 | rngI := new(RandomInc) 463 | rngR := new(RandomInc) 464 | *rngR = 1 465 | 466 | staticI, _ := cs.GenerateKeypair(rngI) 467 | staticR, _ := cs.GenerateKeypair(rngR) 468 | prologue := []byte{0x01, 0x02, 0x03} 469 | psk := []byte{0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23} 470 | 471 | hsI, _ := NewHandshakeState(Config{ 472 | CipherSuite: cs, 473 | Random: rngI, 474 | Pattern: HandshakeXX, 475 | Initiator: true, 476 | Prologue: prologue, 477 | PresharedKey: psk, 478 | StaticKeypair: staticI, 479 | }) 480 | hsR, _ := NewHandshakeState(Config{ 481 | CipherSuite: cs, 482 | Random: rngR, 483 | Pattern: HandshakeXX, 484 | Prologue: prologue, 485 | PresharedKey: psk, 486 | StaticKeypair: staticR, 487 | }) 488 | 489 | msg, _, _, _ := hsI.WriteMessage(nil, []byte("abc")) 490 | c.Assert(msg, HasLen, 51) 491 | res, _, _, err := hsR.ReadMessage(nil, msg) 492 | c.Assert(err, IsNil) 493 | c.Assert(string(res), Equals, "abc") 494 | 495 | msg, _, _, _ = hsR.WriteMessage(nil, []byte("defg")) 496 | c.Assert(msg, HasLen, 100) 497 | res, _, _, err = hsI.ReadMessage(nil, msg) 498 | c.Assert(err, IsNil) 499 | c.Assert(string(res), Equals, "defg") 500 | 501 | msg, _, _, _ = hsI.WriteMessage(nil, nil) 502 | c.Assert(msg, HasLen, 64) 503 | res, _, _, err = hsR.ReadMessage(nil, msg) 504 | c.Assert(err, IsNil) 505 | c.Assert(res, HasLen, 0) 506 | 507 | expected, _ := hex.DecodeString("1b6d7cc3b13bd02217f9cdb98c50870db96281193dca4df570bf6230a603b686fd90d2914c7e797d9276ef8fb34b0c9d87faa048ce4bc7e7af21b6a450352275") 508 | c.Assert(msg, DeepEquals, expected) 509 | } 510 | 511 | func (NoiseSuite) TestHandshakeRollback(c *C) { 512 | cs := NewCipherSuite(DH25519, CipherAESGCM, HashSHA512) 513 | rngI := new(RandomInc) 514 | rngR := new(RandomInc) 515 | *rngR = 1 516 | 517 | hsI, _ := NewHandshakeState(Config{ 518 | CipherSuite: cs, 519 | Random: rngI, 520 | Pattern: HandshakeNN, 521 | Initiator: true, 522 | }) 523 | hsR, _ := NewHandshakeState(Config{ 524 | CipherSuite: cs, 525 | Random: rngR, 526 | Pattern: HandshakeNN, 527 | Initiator: false, 528 | }) 529 | 530 | msg, _, _, _ := hsI.WriteMessage(nil, []byte("abc")) 531 | c.Assert(msg, HasLen, 35) 532 | res, _, _, err := hsR.ReadMessage(nil, msg) 533 | c.Assert(err, IsNil) 534 | c.Assert(string(res), Equals, "abc") 535 | 536 | msg, _, _, _ = hsR.WriteMessage(nil, []byte("defg")) 537 | c.Assert(msg, HasLen, 52) 538 | prev := msg[1] 539 | msg[1] = msg[1] + 1 540 | _, _, _, err = hsI.ReadMessage(nil, msg) 541 | c.Assert(err, Not(IsNil)) 542 | msg[1] = prev 543 | res, _, _, err = hsI.ReadMessage(nil, msg) 544 | c.Assert(err, IsNil) 545 | c.Assert(string(res), Equals, "defg") 546 | 547 | expected, _ := hex.DecodeString("07a37cbc142093c8b755dc1b10e86cb426374ad16aa853ed0bdfc0b2b86d1c7c5e4dc9545d41b3280f4586a5481829e1e24ec5a0") 548 | c.Assert(msg, DeepEquals, expected) 549 | } 550 | 551 | func (NoiseSuite) TestHandshakeRollback_rs(c *C) { 552 | cs := NewCipherSuite(DH25519, CipherAESGCM, HashSHA512) 553 | rngI := new(RandomInc) 554 | rngR := new(RandomInc) 555 | 556 | staticI, _ := cs.GenerateKeypair(rngI) 557 | staticR, _ := cs.GenerateKeypair(rngR) 558 | 559 | *rngR = 1 560 | 561 | hsI, _ := NewHandshakeState(Config{ 562 | CipherSuite: cs, 563 | Random: rngI, 564 | Pattern: HandshakeIX, 565 | Initiator: true, 566 | StaticKeypair: staticI, 567 | }) 568 | hsR, _ := NewHandshakeState(Config{ 569 | CipherSuite: cs, 570 | Random: rngR, 571 | Pattern: HandshakeIX, 572 | Initiator: false, 573 | StaticKeypair: staticR, 574 | }) 575 | 576 | msg, _, _, _ := hsI.WriteMessage(nil, []byte("abc")) 577 | c.Assert(msg, HasLen, 67) 578 | res, _, _, err := hsR.ReadMessage(nil, msg) 579 | c.Assert(err, IsNil) 580 | c.Assert(string(res), Equals, "abc") 581 | 582 | msg, _, _, _ = hsR.WriteMessage(nil, []byte("defg")) 583 | c.Assert(msg, HasLen, 100) 584 | prev := msg[1] 585 | msg[1] = msg[1] + 1 586 | _, _, _, err = hsI.ReadMessage(nil, msg) 587 | c.Assert(err, Not(IsNil)) 588 | msg[1] = prev 589 | res, _, _, err = hsI.ReadMessage(nil, msg) 590 | c.Assert(err, IsNil) 591 | c.Assert(string(res), Equals, "defg") 592 | 593 | expected, _ := hex.DecodeString("07a37cbc142093c8b755dc1b10e86cb426374ad16aa853ed0bdfc0b2b86d1c7cf66fc41515606de81af64a5364fbc0b2cbd71e0837ea590b72b77ae2caaaa93bc19c167c28236a18e0737d395fe95083e41da26a30a8062faf92ed05bbdc36db2369f19b") 594 | c.Assert(msg, DeepEquals, expected) 595 | } 596 | 597 | func (NoiseSuite) TestSetNonce(c *C) { 598 | cs := NewCipherSuite(DH25519, CipherAESGCM, HashSHA512) 599 | rngI := new(RandomInc) 600 | rngR := new(RandomInc) 601 | *rngR = 1 602 | 603 | hsI, _ := NewHandshakeState(Config{ 604 | CipherSuite: cs, 605 | Random: rngI, 606 | Pattern: HandshakeNN, 607 | Initiator: true, 608 | }) 609 | hsR, _ := NewHandshakeState(Config{ 610 | CipherSuite: cs, 611 | Random: rngR, 612 | Pattern: HandshakeNN, 613 | Initiator: false, 614 | }) 615 | 616 | msg, _, _, _ := hsI.WriteMessage(nil, nil) 617 | res, _, _, err := hsR.ReadMessage(nil, msg) 618 | c.Assert(err, IsNil) 619 | c.Assert(res, HasLen, 0) 620 | 621 | msg, csR0, csR1, _ := hsR.WriteMessage(nil, nil) 622 | res, csI0, csI1, err := hsI.ReadMessage(nil, msg) 623 | c.Assert(err, IsNil) 624 | c.Assert(res, HasLen, 0) 625 | 626 | c.Assert(csI0.Nonce(), Equals, uint64(0)) 627 | c.Assert(csI1.Nonce(), Equals, uint64(0)) 628 | c.Assert(csR0.Nonce(), Equals, uint64(0)) 629 | c.Assert(csR1.Nonce(), Equals, uint64(0)) 630 | 631 | const n = 1234 632 | clientMessage := []byte("msg1") 633 | csI0.SetNonce(n) 634 | msg, err = csI0.Encrypt(nil, nil, clientMessage) 635 | c.Assert(err, IsNil) 636 | // decrypt with incorrect nonce 637 | _, err = csR0.Decrypt(nil, nil, msg) 638 | c.Assert(err, NotNil) 639 | // decrypt with correct nonce 640 | csR0.SetNonce(n) 641 | res, err = csR0.Decrypt(nil, nil, msg) 642 | c.Assert(err, IsNil) 643 | c.Assert(string(clientMessage), Equals, string(res)) 644 | 645 | c.Assert(csI0.Nonce(), Equals, uint64(n+1)) 646 | c.Assert(csI1.Nonce(), Equals, uint64(0)) 647 | c.Assert(csR0.Nonce(), Equals, uint64(n+1)) 648 | c.Assert(csR1.Nonce(), Equals, uint64(0)) 649 | 650 | serverMessage := []byte("msg2") 651 | csR1.SetNonce(MaxNonce + 1) 652 | _, err = csR1.Encrypt(nil, nil, serverMessage) 653 | c.Assert(err, Equals, ErrMaxNonce) 654 | } 655 | 656 | func (NoiseSuite) TestRekey(c *C) { 657 | rng := new(RandomInc) 658 | 659 | clientStaticKeypair, _ := DH25519.GenerateKeypair(rng) 660 | clientConfig := Config{} 661 | clientConfig.CipherSuite = NewCipherSuite(DH25519, CipherChaChaPoly, HashBLAKE2b) 662 | clientConfig.Random = rng 663 | clientConfig.Pattern = HandshakeNN 664 | clientConfig.Initiator = true 665 | clientConfig.Prologue = []byte{0} 666 | clientConfig.StaticKeypair = clientStaticKeypair 667 | clientConfig.EphemeralKeypair, _ = DH25519.GenerateKeypair(rng) 668 | clientHs, _ := NewHandshakeState(clientConfig) 669 | 670 | serverStaticKeypair, _ := DH25519.GenerateKeypair(rng) 671 | serverConfig := Config{} 672 | serverConfig.CipherSuite = NewCipherSuite(DH25519, CipherChaChaPoly, HashBLAKE2b) 673 | serverConfig.Random = rng 674 | serverConfig.Pattern = HandshakeNN 675 | serverConfig.Initiator = false 676 | serverConfig.Prologue = []byte{0} 677 | serverConfig.StaticKeypair = serverStaticKeypair 678 | serverConfig.EphemeralKeypair, _ = DH25519.GenerateKeypair(rng) 679 | serverHs, _ := NewHandshakeState(serverConfig) 680 | 681 | clientHsMsg, _, _, _ := clientHs.WriteMessage(nil, nil) 682 | c.Assert(32, Equals, len(clientHsMsg)) 683 | 684 | serverHsResult, _, _, err := serverHs.ReadMessage(nil, clientHsMsg) 685 | c.Assert(err, IsNil) 686 | c.Assert(0, Equals, len(serverHsResult)) 687 | 688 | serverHsMsg, csR0, csR1, _ := serverHs.WriteMessage(nil, nil) 689 | c.Assert(48, Equals, len(serverHsMsg)) 690 | 691 | clientHsResult, csI0, csI1, err := clientHs.ReadMessage(nil, serverHsMsg) 692 | c.Assert(err, IsNil) 693 | c.Assert(0, Equals, len(clientHsResult)) 694 | 695 | clientMessage := []byte("hello") 696 | msg, err := csI0.Encrypt(nil, nil, clientMessage) 697 | c.Assert(err, IsNil) 698 | res, err := csR0.Decrypt(nil, nil, msg) 699 | c.Assert(err, IsNil) 700 | c.Assert(string(clientMessage), Equals, string(res)) 701 | 702 | oldK := csI0.k 703 | csI0.Rekey() 704 | c.Assert(oldK, Not(Equals), csI0.k) 705 | csR0.Rekey() 706 | 707 | clientMessage = []byte("hello again") 708 | msg, err = csI0.Encrypt(nil, nil, clientMessage) 709 | c.Assert(err, IsNil) 710 | res, err = csR0.Decrypt(nil, nil, msg) 711 | c.Assert(err, IsNil) 712 | c.Assert(string(clientMessage), Equals, string(res)) 713 | 714 | serverMessage := []byte("bye") 715 | msg, err = csR1.Encrypt(nil, nil, serverMessage) 716 | c.Assert(err, IsNil) 717 | res, err = csI1.Decrypt(nil, nil, msg) 718 | c.Assert(err, IsNil) 719 | c.Assert(string(serverMessage), Equals, string(res)) 720 | 721 | preNonce := csR1.Nonce() 722 | 723 | csR1.Rekey() 724 | csI1.Rekey() 725 | 726 | postNonce := csR1.Nonce() 727 | c.Assert(preNonce, Equals, postNonce) 728 | 729 | serverMessage = []byte("bye bye") 730 | msg, err = csR1.Encrypt(nil, nil, serverMessage) 731 | c.Assert(err, IsNil) 732 | res, err = csI1.Decrypt(nil, nil, msg) 733 | c.Assert(err, IsNil) 734 | c.Assert(string(serverMessage), Equals, string(res)) 735 | 736 | // only rekey one side, test for failure 737 | csR1.Rekey() 738 | serverMessage = []byte("bye again") 739 | msg, err = csR1.Encrypt(nil, nil, serverMessage) 740 | c.Assert(err, IsNil) 741 | res, err = csI1.Decrypt(nil, nil, msg) 742 | c.Assert(err, NotNil) 743 | c.Assert(string(serverMessage), Not(Equals), string(res)) 744 | 745 | // check nonce overflow handling 746 | csI1.n = math.MaxUint64 747 | msg, err = csI1.Encrypt(nil, nil, nil) 748 | c.Assert(err, Equals, ErrMaxNonce) 749 | c.Assert(msg, IsNil) 750 | msg, err = csI1.Decrypt(nil, nil, nil) 751 | c.Assert(err, Equals, ErrMaxNonce) 752 | c.Assert(msg, IsNil) 753 | } 754 | -------------------------------------------------------------------------------- /patterns.go: -------------------------------------------------------------------------------- 1 | package noise 2 | 3 | var HandshakeNN = HandshakePattern{ 4 | Name: "NN", 5 | Messages: [][]MessagePattern{ 6 | {MessagePatternE}, 7 | {MessagePatternE, MessagePatternDHEE}, 8 | }, 9 | } 10 | 11 | var HandshakeKN = HandshakePattern{ 12 | Name: "KN", 13 | InitiatorPreMessages: []MessagePattern{MessagePatternS}, 14 | Messages: [][]MessagePattern{ 15 | {MessagePatternE}, 16 | {MessagePatternE, MessagePatternDHEE, MessagePatternDHSE}, 17 | }, 18 | } 19 | 20 | var HandshakeNK = HandshakePattern{ 21 | Name: "NK", 22 | ResponderPreMessages: []MessagePattern{MessagePatternS}, 23 | Messages: [][]MessagePattern{ 24 | {MessagePatternE, MessagePatternDHES}, 25 | {MessagePatternE, MessagePatternDHEE}, 26 | }, 27 | } 28 | 29 | var HandshakeKK = HandshakePattern{ 30 | Name: "KK", 31 | InitiatorPreMessages: []MessagePattern{MessagePatternS}, 32 | ResponderPreMessages: []MessagePattern{MessagePatternS}, 33 | Messages: [][]MessagePattern{ 34 | {MessagePatternE, MessagePatternDHES, MessagePatternDHSS}, 35 | {MessagePatternE, MessagePatternDHEE, MessagePatternDHSE}, 36 | }, 37 | } 38 | 39 | var HandshakeNX = HandshakePattern{ 40 | Name: "NX", 41 | Messages: [][]MessagePattern{ 42 | {MessagePatternE}, 43 | {MessagePatternE, MessagePatternDHEE, MessagePatternS, MessagePatternDHES}, 44 | }, 45 | } 46 | 47 | var HandshakeKX = HandshakePattern{ 48 | Name: "KX", 49 | InitiatorPreMessages: []MessagePattern{MessagePatternS}, 50 | Messages: [][]MessagePattern{ 51 | {MessagePatternE}, 52 | {MessagePatternE, MessagePatternDHEE, MessagePatternDHSE, MessagePatternS, MessagePatternDHES}, 53 | }, 54 | } 55 | 56 | var HandshakeXN = HandshakePattern{ 57 | Name: "XN", 58 | Messages: [][]MessagePattern{ 59 | {MessagePatternE}, 60 | {MessagePatternE, MessagePatternDHEE}, 61 | {MessagePatternS, MessagePatternDHSE}, 62 | }, 63 | } 64 | 65 | var HandshakeIN = HandshakePattern{ 66 | Name: "IN", 67 | Messages: [][]MessagePattern{ 68 | {MessagePatternE, MessagePatternS}, 69 | {MessagePatternE, MessagePatternDHEE, MessagePatternDHSE}, 70 | }, 71 | } 72 | 73 | var HandshakeXK = HandshakePattern{ 74 | Name: "XK", 75 | ResponderPreMessages: []MessagePattern{MessagePatternS}, 76 | Messages: [][]MessagePattern{ 77 | {MessagePatternE, MessagePatternDHES}, 78 | {MessagePatternE, MessagePatternDHEE}, 79 | {MessagePatternS, MessagePatternDHSE}, 80 | }, 81 | } 82 | 83 | var HandshakeIK = HandshakePattern{ 84 | Name: "IK", 85 | ResponderPreMessages: []MessagePattern{MessagePatternS}, 86 | Messages: [][]MessagePattern{ 87 | {MessagePatternE, MessagePatternDHES, MessagePatternS, MessagePatternDHSS}, 88 | {MessagePatternE, MessagePatternDHEE, MessagePatternDHSE}, 89 | }, 90 | } 91 | 92 | var HandshakeXX = HandshakePattern{ 93 | Name: "XX", 94 | Messages: [][]MessagePattern{ 95 | {MessagePatternE}, 96 | {MessagePatternE, MessagePatternDHEE, MessagePatternS, MessagePatternDHES}, 97 | {MessagePatternS, MessagePatternDHSE}, 98 | }, 99 | } 100 | 101 | var HandshakeXXfallback = HandshakePattern{ 102 | Name: "XXfallback", 103 | ResponderPreMessages: []MessagePattern{MessagePatternE}, 104 | Messages: [][]MessagePattern{ 105 | {MessagePatternE, MessagePatternDHEE, MessagePatternS, MessagePatternDHSE}, 106 | {MessagePatternS, MessagePatternDHES}, 107 | }, 108 | } 109 | 110 | var HandshakeIX = HandshakePattern{ 111 | Name: "IX", 112 | Messages: [][]MessagePattern{ 113 | {MessagePatternE, MessagePatternS}, 114 | {MessagePatternE, MessagePatternDHEE, MessagePatternDHSE, MessagePatternS, MessagePatternDHES}, 115 | }, 116 | } 117 | 118 | var HandshakeN = HandshakePattern{ 119 | Name: "N", 120 | ResponderPreMessages: []MessagePattern{MessagePatternS}, 121 | Messages: [][]MessagePattern{ 122 | {MessagePatternE, MessagePatternDHES}, 123 | }, 124 | } 125 | 126 | var HandshakeK = HandshakePattern{ 127 | Name: "K", 128 | InitiatorPreMessages: []MessagePattern{MessagePatternS}, 129 | ResponderPreMessages: []MessagePattern{MessagePatternS}, 130 | Messages: [][]MessagePattern{ 131 | {MessagePatternE, MessagePatternDHES, MessagePatternDHSS}, 132 | }, 133 | } 134 | 135 | var HandshakeX = HandshakePattern{ 136 | Name: "X", 137 | ResponderPreMessages: []MessagePattern{MessagePatternS}, 138 | Messages: [][]MessagePattern{ 139 | {MessagePatternE, MessagePatternDHES, MessagePatternS, MessagePatternDHSS}, 140 | }, 141 | } 142 | -------------------------------------------------------------------------------- /state.go: -------------------------------------------------------------------------------- 1 | // Package noise implements the Noise Protocol Framework. 2 | // 3 | // Noise is a low-level framework for building crypto protocols. Noise protocols 4 | // support mutual and optional authentication, identity hiding, forward secrecy, 5 | // zero round-trip encryption, and other advanced features. For more details, 6 | // visit https://noiseprotocol.org. 7 | package noise 8 | 9 | import ( 10 | "crypto/rand" 11 | "errors" 12 | "fmt" 13 | "io" 14 | "math" 15 | ) 16 | 17 | // A CipherState provides symmetric encryption and decryption after a successful 18 | // handshake. 19 | type CipherState struct { 20 | cs CipherSuite 21 | c Cipher 22 | k [32]byte 23 | n uint64 24 | 25 | invalid bool 26 | } 27 | 28 | // MaxNonce is the maximum value of n that is allowed. ErrMaxNonce is returned 29 | // by Encrypt and Decrypt after this has been reached. 2^64-1 is reserved for rekeys. 30 | const MaxNonce = uint64(math.MaxUint64) - 1 31 | 32 | var ErrMaxNonce = errors.New("noise: cipherstate has reached maximum n, a new handshake must be performed") 33 | var ErrCipherSuiteCopied = errors.New("noise: CipherSuite has been copied, state is invalid") 34 | 35 | // UnsafeNewCipherState reconstructs a CipherState from exported components. 36 | // It is important that, when resuming from an exported state, care is taken 37 | // to synchronize the nonce state and not allow rollbacks. 38 | func UnsafeNewCipherState(cs CipherSuite, k [32]byte, n uint64) *CipherState { 39 | return &CipherState{ 40 | cs: cs, 41 | c: cs.Cipher(k), 42 | k: k, 43 | n: n, 44 | } 45 | } 46 | 47 | // Encrypt encrypts the plaintext and then appends the ciphertext and an 48 | // authentication tag across the ciphertext and optional authenticated data to 49 | // out. This method automatically increments the nonce after every call, so 50 | // messages must be decrypted in the same order. ErrMaxNonce is returned after 51 | // the maximum nonce of 2^64-2 is reached. 52 | func (s *CipherState) Encrypt(out, ad, plaintext []byte) ([]byte, error) { 53 | if s.invalid { 54 | return nil, ErrCipherSuiteCopied 55 | } 56 | if s.n > MaxNonce { 57 | return nil, ErrMaxNonce 58 | } 59 | out = s.c.Encrypt(out, s.n, ad, plaintext) 60 | s.n++ 61 | return out, nil 62 | } 63 | 64 | // Decrypt checks the authenticity of the ciphertext and authenticated data and 65 | // then decrypts and appends the plaintext to out. This method automatically 66 | // increments the nonce after every call, messages must be provided in the same 67 | // order that they were encrypted with no missing messages. ErrMaxNonce is 68 | // returned after the maximum nonce of 2^64-2 is reached. 69 | func (s *CipherState) Decrypt(out, ad, ciphertext []byte) ([]byte, error) { 70 | if s.invalid { 71 | return nil, ErrCipherSuiteCopied 72 | } 73 | if s.n > MaxNonce { 74 | return nil, ErrMaxNonce 75 | } 76 | out, err := s.c.Decrypt(out, s.n, ad, ciphertext) 77 | if err != nil { 78 | return nil, err 79 | } 80 | s.n++ 81 | return out, nil 82 | } 83 | 84 | // Cipher returns the low-level symmetric encryption primitive. It should only 85 | // be used if nonces need to be managed manually, for example with a network 86 | // protocol that can deliver out-of-order messages. This is dangerous, users 87 | // must ensure that they are incrementing a nonce after every encrypt operation. 88 | // After calling this method, it is an error to call Encrypt/Decrypt on the 89 | // CipherState. 90 | func (s *CipherState) Cipher() Cipher { 91 | s.invalid = true 92 | return s.c 93 | } 94 | 95 | // Nonce returns the current value of n. This can be used to determine if a 96 | // new handshake should be performed due to approaching MaxNonce. 97 | func (s *CipherState) Nonce() uint64 { 98 | return s.n 99 | } 100 | 101 | // SetNonce sets the current value of n. 102 | func (s *CipherState) SetNonce(n uint64) { 103 | s.n = n 104 | } 105 | 106 | // UnsafeKey returns the current value of k. This exports the current key for the 107 | // CipherState. Intended to be used alongside UnsafeNewCipherState to resume a 108 | // CipherState at a later point. 109 | func (s *CipherState) UnsafeKey() [32]byte { 110 | return s.k 111 | } 112 | 113 | func (s *CipherState) Rekey() { 114 | var zeros [32]byte 115 | var out []byte 116 | out = s.c.Encrypt(out, math.MaxUint64, []byte{}, zeros[:]) 117 | copy(s.k[:], out[:32]) 118 | s.c = s.cs.Cipher(s.k) 119 | } 120 | 121 | type symmetricState struct { 122 | CipherState 123 | hasK bool 124 | ck []byte 125 | h []byte 126 | 127 | prevCK []byte 128 | prevH []byte 129 | } 130 | 131 | func (s *symmetricState) InitializeSymmetric(handshakeName []byte) { 132 | h := s.cs.Hash() 133 | if len(handshakeName) <= h.Size() { 134 | s.h = make([]byte, h.Size()) 135 | copy(s.h, handshakeName) 136 | } else { 137 | h.Write(handshakeName) 138 | s.h = h.Sum(nil) 139 | } 140 | s.ck = make([]byte, len(s.h)) 141 | copy(s.ck, s.h) 142 | } 143 | 144 | func (s *symmetricState) MixKey(dhOutput []byte) { 145 | s.n = 0 146 | s.hasK = true 147 | var hk []byte 148 | s.ck, hk, _ = hkdf(s.cs.Hash, 2, s.ck[:0], s.k[:0], nil, s.ck, dhOutput) 149 | copy(s.k[:], hk) 150 | s.c = s.cs.Cipher(s.k) 151 | } 152 | 153 | func (s *symmetricState) MixHash(data []byte) { 154 | h := s.cs.Hash() 155 | h.Write(s.h) 156 | h.Write(data) 157 | s.h = h.Sum(s.h[:0]) 158 | } 159 | 160 | func (s *symmetricState) MixKeyAndHash(data []byte) { 161 | var hk []byte 162 | var temp []byte 163 | s.ck, temp, hk = hkdf(s.cs.Hash, 3, s.ck[:0], temp, s.k[:0], s.ck, data) 164 | s.MixHash(temp) 165 | copy(s.k[:], hk) 166 | s.c = s.cs.Cipher(s.k) 167 | s.n = 0 168 | s.hasK = true 169 | } 170 | 171 | func (s *symmetricState) EncryptAndHash(out, plaintext []byte) ([]byte, error) { 172 | if !s.hasK { 173 | s.MixHash(plaintext) 174 | return append(out, plaintext...), nil 175 | } 176 | ciphertext, err := s.Encrypt(out, s.h, plaintext) 177 | if err != nil { 178 | return nil, err 179 | } 180 | s.MixHash(ciphertext[len(out):]) 181 | return ciphertext, nil 182 | } 183 | 184 | func (s *symmetricState) DecryptAndHash(out, data []byte) ([]byte, error) { 185 | if !s.hasK { 186 | s.MixHash(data) 187 | return append(out, data...), nil 188 | } 189 | plaintext, err := s.Decrypt(out, s.h, data) 190 | if err != nil { 191 | return nil, err 192 | } 193 | s.MixHash(data) 194 | return plaintext, nil 195 | } 196 | 197 | func (s *symmetricState) Split() (*CipherState, *CipherState) { 198 | s1, s2 := &CipherState{cs: s.cs}, &CipherState{cs: s.cs} 199 | hk1, hk2, _ := hkdf(s.cs.Hash, 2, s1.k[:0], s2.k[:0], nil, s.ck, nil) 200 | copy(s1.k[:], hk1) 201 | copy(s2.k[:], hk2) 202 | s1.c = s.cs.Cipher(s1.k) 203 | s2.c = s.cs.Cipher(s2.k) 204 | return s1, s2 205 | } 206 | 207 | func (s *symmetricState) Checkpoint() { 208 | if len(s.ck) > cap(s.prevCK) { 209 | s.prevCK = make([]byte, len(s.ck)) 210 | } 211 | s.prevCK = s.prevCK[:len(s.ck)] 212 | copy(s.prevCK, s.ck) 213 | 214 | if len(s.h) > cap(s.prevH) { 215 | s.prevH = make([]byte, len(s.h)) 216 | } 217 | s.prevH = s.prevH[:len(s.h)] 218 | copy(s.prevH, s.h) 219 | } 220 | 221 | func (s *symmetricState) Rollback() { 222 | s.ck = s.ck[:len(s.prevCK)] 223 | copy(s.ck, s.prevCK) 224 | s.h = s.h[:len(s.prevH)] 225 | copy(s.h, s.prevH) 226 | } 227 | 228 | // A MessagePattern is a single message or operation used in a Noise handshake. 229 | type MessagePattern int 230 | 231 | // A HandshakePattern is a list of messages and operations that are used to 232 | // perform a specific Noise handshake. 233 | type HandshakePattern struct { 234 | Name string 235 | InitiatorPreMessages []MessagePattern 236 | ResponderPreMessages []MessagePattern 237 | Messages [][]MessagePattern 238 | } 239 | 240 | const ( 241 | MessagePatternS MessagePattern = iota 242 | MessagePatternE 243 | MessagePatternDHEE 244 | MessagePatternDHES 245 | MessagePatternDHSE 246 | MessagePatternDHSS 247 | MessagePatternPSK 248 | ) 249 | 250 | // MaxMsgLen is the maximum number of bytes that can be sent in a single Noise 251 | // message. 252 | const MaxMsgLen = 65535 253 | 254 | // A HandshakeState tracks the state of a Noise handshake. It may be discarded 255 | // after the handshake is complete. 256 | type HandshakeState struct { 257 | ss symmetricState 258 | s DHKey // local static keypair 259 | e DHKey // local ephemeral keypair 260 | rs []byte // remote party's static public key 261 | re []byte // remote party's ephemeral public key 262 | psk []byte // preshared key, maybe zero length 263 | willPsk bool // indicates if preshared key will be used (even if not yet set) 264 | messagePatterns [][]MessagePattern 265 | shouldWrite bool 266 | initiator bool 267 | msgIdx int 268 | rng io.Reader 269 | } 270 | 271 | // A Config provides the details necessary to process a Noise handshake. It is 272 | // never modified by this package, and can be reused. 273 | type Config struct { 274 | // CipherSuite is the set of cryptographic primitives that will be used. 275 | CipherSuite CipherSuite 276 | 277 | // Random is the source for cryptographically appropriate random bytes. If 278 | // zero, it is automatically configured. 279 | Random io.Reader 280 | 281 | // Pattern is the pattern for the handshake. 282 | Pattern HandshakePattern 283 | 284 | // Initiator must be true if the first message in the handshake will be sent 285 | // by this peer. 286 | Initiator bool 287 | 288 | // Prologue is an optional message that has already be communicated and must 289 | // be identical on both sides for the handshake to succeed. 290 | Prologue []byte 291 | 292 | // PresharedKey is the optional preshared key for the handshake. 293 | PresharedKey []byte 294 | 295 | // PresharedKeyPlacement specifies the placement position of the PSK token 296 | // when PresharedKey is specified 297 | PresharedKeyPlacement int 298 | 299 | // StaticKeypair is this peer's static keypair, required if part of the 300 | // handshake. 301 | StaticKeypair DHKey 302 | 303 | // EphemeralKeypair is this peer's ephemeral keypair that was provided as 304 | // a pre-message in the handshake. 305 | EphemeralKeypair DHKey 306 | 307 | // PeerStatic is the static public key of the remote peer that was provided 308 | // as a pre-message in the handshake. 309 | PeerStatic []byte 310 | 311 | // PeerEphemeral is the ephemeral public key of the remote peer that was 312 | // provided as a pre-message in the handshake. 313 | PeerEphemeral []byte 314 | } 315 | 316 | // NewHandshakeState starts a new handshake using the provided configuration. 317 | func NewHandshakeState(c Config) (*HandshakeState, error) { 318 | hs := &HandshakeState{ 319 | s: c.StaticKeypair, 320 | e: c.EphemeralKeypair, 321 | rs: c.PeerStatic, 322 | messagePatterns: c.Pattern.Messages, 323 | shouldWrite: c.Initiator, 324 | initiator: c.Initiator, 325 | rng: c.Random, 326 | } 327 | if hs.rng == nil { 328 | hs.rng = rand.Reader 329 | } 330 | if len(c.PeerEphemeral) > 0 { 331 | hs.re = make([]byte, len(c.PeerEphemeral)) 332 | copy(hs.re, c.PeerEphemeral) 333 | } 334 | hs.ss.cs = c.CipherSuite 335 | 336 | pskModifier := "" 337 | // NB: for psk{0,1} we must have preshared key set in configuration as its needed in the first 338 | // message. For psk{2+} we may not know the correct psk yet so it might not be set. 339 | if len(c.PresharedKey) > 0 || c.PresharedKeyPlacement >= 2 { 340 | hs.willPsk = true 341 | if len(c.PresharedKey) > 0 { 342 | if err := hs.SetPresharedKey(c.PresharedKey); err != nil { 343 | return nil, err 344 | } 345 | } 346 | 347 | pskModifier = fmt.Sprintf("psk%d", c.PresharedKeyPlacement) 348 | hs.messagePatterns = append([][]MessagePattern(nil), hs.messagePatterns...) 349 | if c.PresharedKeyPlacement == 0 { 350 | hs.messagePatterns[0] = append([]MessagePattern{MessagePatternPSK}, hs.messagePatterns[0]...) 351 | } else { 352 | hs.messagePatterns[c.PresharedKeyPlacement-1] = append(hs.messagePatterns[c.PresharedKeyPlacement-1], MessagePatternPSK) 353 | } 354 | } 355 | 356 | hs.ss.InitializeSymmetric([]byte("Noise_" + c.Pattern.Name + pskModifier + "_" + string(hs.ss.cs.Name()))) 357 | hs.ss.MixHash(c.Prologue) 358 | for _, m := range c.Pattern.InitiatorPreMessages { 359 | switch { 360 | case c.Initiator && m == MessagePatternS: 361 | hs.ss.MixHash(hs.s.Public) 362 | case c.Initiator && m == MessagePatternE: 363 | hs.ss.MixHash(hs.e.Public) 364 | case !c.Initiator && m == MessagePatternS: 365 | hs.ss.MixHash(hs.rs) 366 | case !c.Initiator && m == MessagePatternE: 367 | hs.ss.MixHash(hs.re) 368 | } 369 | } 370 | for _, m := range c.Pattern.ResponderPreMessages { 371 | switch { 372 | case !c.Initiator && m == MessagePatternS: 373 | hs.ss.MixHash(hs.s.Public) 374 | case !c.Initiator && m == MessagePatternE: 375 | hs.ss.MixHash(hs.e.Public) 376 | case c.Initiator && m == MessagePatternS: 377 | hs.ss.MixHash(hs.rs) 378 | case c.Initiator && m == MessagePatternE: 379 | hs.ss.MixHash(hs.re) 380 | } 381 | } 382 | return hs, nil 383 | } 384 | 385 | // WriteMessage appends a handshake message to out. The message will include the 386 | // optional payload if provided. If the handshake is completed by the call, two 387 | // CipherStates will be returned, one is used for encryption of messages to the 388 | // remote peer, the other is used for decryption of messages from the remote 389 | // peer. It is an error to call this method out of sync with the handshake 390 | // pattern. 391 | func (s *HandshakeState) WriteMessage(out, payload []byte) ([]byte, *CipherState, *CipherState, error) { 392 | if !s.shouldWrite { 393 | return nil, nil, nil, errors.New("noise: unexpected call to WriteMessage should be ReadMessage") 394 | } 395 | if s.msgIdx > len(s.messagePatterns)-1 { 396 | return nil, nil, nil, errors.New("noise: no handshake messages left") 397 | } 398 | if len(payload) > MaxMsgLen { 399 | return nil, nil, nil, errors.New("noise: message is too long") 400 | } 401 | 402 | var err error 403 | for _, msg := range s.messagePatterns[s.msgIdx] { 404 | switch msg { 405 | case MessagePatternE: 406 | e, err := s.ss.cs.GenerateKeypair(s.rng) 407 | if err != nil { 408 | return nil, nil, nil, err 409 | } 410 | s.e = e 411 | out = append(out, s.e.Public...) 412 | s.ss.MixHash(s.e.Public) 413 | if s.willPsk { 414 | s.ss.MixKey(s.e.Public) 415 | } 416 | case MessagePatternS: 417 | if len(s.s.Public) == 0 { 418 | return nil, nil, nil, errors.New("noise: invalid state, s.Public is nil") 419 | } 420 | out, err = s.ss.EncryptAndHash(out, s.s.Public) 421 | if err != nil { 422 | return nil, nil, nil, err 423 | } 424 | case MessagePatternDHEE: 425 | dh, err := s.ss.cs.DH(s.e.Private, s.re) 426 | if err != nil { 427 | return nil, nil, nil, err 428 | } 429 | s.ss.MixKey(dh) 430 | case MessagePatternDHES: 431 | if s.initiator { 432 | dh, err := s.ss.cs.DH(s.e.Private, s.rs) 433 | if err != nil { 434 | return nil, nil, nil, err 435 | } 436 | s.ss.MixKey(dh) 437 | } else { 438 | dh, err := s.ss.cs.DH(s.s.Private, s.re) 439 | if err != nil { 440 | return nil, nil, nil, err 441 | } 442 | s.ss.MixKey(dh) 443 | } 444 | case MessagePatternDHSE: 445 | if s.initiator { 446 | dh, err := s.ss.cs.DH(s.s.Private, s.re) 447 | if err != nil { 448 | return nil, nil, nil, err 449 | } 450 | s.ss.MixKey(dh) 451 | } else { 452 | dh, err := s.ss.cs.DH(s.e.Private, s.rs) 453 | if err != nil { 454 | return nil, nil, nil, err 455 | } 456 | s.ss.MixKey(dh) 457 | } 458 | case MessagePatternDHSS: 459 | dh, err := s.ss.cs.DH(s.s.Private, s.rs) 460 | if err != nil { 461 | return nil, nil, nil, err 462 | } 463 | s.ss.MixKey(dh) 464 | case MessagePatternPSK: 465 | if len(s.psk) == 0 { 466 | return nil, nil, nil, errors.New("noise: cannot send psk message without psk set") 467 | } 468 | s.ss.MixKeyAndHash(s.psk) 469 | } 470 | } 471 | s.shouldWrite = false 472 | s.msgIdx++ 473 | out, err = s.ss.EncryptAndHash(out, payload) 474 | if err != nil { 475 | return nil, nil, nil, err 476 | } 477 | 478 | if s.msgIdx >= len(s.messagePatterns) { 479 | cs1, cs2 := s.ss.Split() 480 | return out, cs1, cs2, nil 481 | } 482 | 483 | return out, nil, nil, nil 484 | } 485 | 486 | // ErrShortMessage is returned by ReadMessage if a message is not as long as it should be. 487 | var ErrShortMessage = errors.New("noise: message is too short") 488 | 489 | func (s *HandshakeState) SetPresharedKey(psk []byte) error { 490 | if len(psk) != 32 { 491 | return errors.New("noise: specification mandates 256-bit preshared keys") 492 | } 493 | s.psk = make([]byte, 32) 494 | copy(s.psk, psk) 495 | return nil 496 | } 497 | 498 | // ReadMessage processes a received handshake message and appends the payload, 499 | // if any to out. If the handshake is completed by the call, two CipherStates 500 | // will be returned, one is used for encryption of messages to the remote peer, 501 | // the other is used for decryption of messages from the remote peer. It is an 502 | // error to call this method out of sync with the handshake pattern. 503 | func (s *HandshakeState) ReadMessage(out, message []byte) ([]byte, *CipherState, *CipherState, error) { 504 | if s.shouldWrite { 505 | return nil, nil, nil, errors.New("noise: unexpected call to ReadMessage should be WriteMessage") 506 | } 507 | if s.msgIdx > len(s.messagePatterns)-1 { 508 | return nil, nil, nil, errors.New("noise: no handshake messages left") 509 | } 510 | 511 | rsSet := false 512 | s.ss.Checkpoint() 513 | 514 | var err error 515 | for _, msg := range s.messagePatterns[s.msgIdx] { 516 | switch msg { 517 | case MessagePatternE, MessagePatternS: 518 | expected := s.ss.cs.DHLen() 519 | if msg == MessagePatternS && s.ss.hasK { 520 | expected += 16 521 | } 522 | if len(message) < expected { 523 | return nil, nil, nil, ErrShortMessage 524 | } 525 | switch msg { 526 | case MessagePatternE: 527 | if cap(s.re) < s.ss.cs.DHLen() { 528 | s.re = make([]byte, s.ss.cs.DHLen()) 529 | } 530 | s.re = s.re[:s.ss.cs.DHLen()] 531 | copy(s.re, message) 532 | s.ss.MixHash(s.re) 533 | if s.willPsk { 534 | s.ss.MixKey(s.re) 535 | } 536 | case MessagePatternS: 537 | if len(s.rs) > 0 { 538 | return nil, nil, nil, errors.New("noise: invalid state, rs is not nil") 539 | } 540 | s.rs, err = s.ss.DecryptAndHash(s.rs[:0], message[:expected]) 541 | rsSet = true 542 | } 543 | if err != nil { 544 | s.ss.Rollback() 545 | if rsSet { 546 | s.rs = nil 547 | } 548 | return nil, nil, nil, err 549 | } 550 | message = message[expected:] 551 | case MessagePatternDHEE: 552 | dh, err := s.ss.cs.DH(s.e.Private, s.re) 553 | if err != nil { 554 | return nil, nil, nil, err 555 | } 556 | s.ss.MixKey(dh) 557 | case MessagePatternDHES: 558 | if s.initiator { 559 | dh, err := s.ss.cs.DH(s.e.Private, s.rs) 560 | if err != nil { 561 | return nil, nil, nil, err 562 | } 563 | s.ss.MixKey(dh) 564 | } else { 565 | dh, err := s.ss.cs.DH(s.s.Private, s.re) 566 | if err != nil { 567 | return nil, nil, nil, err 568 | } 569 | s.ss.MixKey(dh) 570 | } 571 | case MessagePatternDHSE: 572 | if s.initiator { 573 | dh, err := s.ss.cs.DH(s.s.Private, s.re) 574 | if err != nil { 575 | return nil, nil, nil, err 576 | } 577 | s.ss.MixKey(dh) 578 | } else { 579 | dh, err := s.ss.cs.DH(s.e.Private, s.rs) 580 | if err != nil { 581 | return nil, nil, nil, err 582 | } 583 | s.ss.MixKey(dh) 584 | } 585 | case MessagePatternDHSS: 586 | dh, err := s.ss.cs.DH(s.s.Private, s.rs) 587 | if err != nil { 588 | return nil, nil, nil, err 589 | } 590 | s.ss.MixKey(dh) 591 | case MessagePatternPSK: 592 | s.ss.MixKeyAndHash(s.psk) 593 | } 594 | } 595 | out, err = s.ss.DecryptAndHash(out, message) 596 | if err != nil { 597 | s.ss.Rollback() 598 | if rsSet { 599 | s.rs = nil 600 | } 601 | return nil, nil, nil, err 602 | } 603 | s.shouldWrite = true 604 | s.msgIdx++ 605 | 606 | if s.msgIdx >= len(s.messagePatterns) { 607 | cs1, cs2 := s.ss.Split() 608 | return out, cs1, cs2, nil 609 | } 610 | 611 | return out, nil, nil, nil 612 | } 613 | 614 | // ChannelBinding provides a value that uniquely identifies the session and can 615 | // be used as a channel binding. It is an error to call this method before the 616 | // handshake is complete. 617 | func (s *HandshakeState) ChannelBinding() []byte { 618 | return s.ss.h 619 | } 620 | 621 | // PeerStatic returns the static key provided by the remote peer during 622 | // a handshake. It is an error to call this method if a handshake message 623 | // containing a static key has not been read. 624 | func (s *HandshakeState) PeerStatic() []byte { 625 | return s.rs 626 | } 627 | 628 | // MessageIndex returns the current handshake message id 629 | func (s *HandshakeState) MessageIndex() int { 630 | return s.msgIdx 631 | } 632 | 633 | // PeerEphemeral returns the ephemeral key provided by the remote peer during 634 | // a handshake. It is an error to call this method if a handshake message 635 | // containing a static key has not been read. 636 | func (s *HandshakeState) PeerEphemeral() []byte { 637 | return s.re 638 | } 639 | 640 | // LocalEphemeral returns the local ephemeral key pair generated during 641 | // a handshake. 642 | func (s *HandshakeState) LocalEphemeral() DHKey { 643 | return s.e 644 | } 645 | -------------------------------------------------------------------------------- /vector_test.go: -------------------------------------------------------------------------------- 1 | package noise 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "encoding/hex" 7 | "fmt" 8 | "io" 9 | "os" 10 | "strconv" 11 | "strings" 12 | 13 | . "gopkg.in/check.v1" 14 | ) 15 | 16 | func mustHex(s []byte) []byte { 17 | res, err := hex.DecodeString(string(s)) 18 | if err != nil { 19 | panic(err) 20 | } 21 | return res 22 | } 23 | 24 | func hexReader(s []byte) io.Reader { 25 | return bytes.NewBuffer(mustHex(s)) 26 | } 27 | 28 | var patterns = make(map[string]HandshakePattern) 29 | var ciphers = map[string]CipherFunc{ 30 | "AESGCM": CipherAESGCM, 31 | "ChaChaPoly": CipherChaChaPoly, 32 | } 33 | var hashes = map[string]HashFunc{ 34 | "SHA256": HashSHA256, 35 | "SHA512": HashSHA512, 36 | "BLAKE2b": HashBLAKE2b, 37 | "BLAKE2s": HashBLAKE2s, 38 | } 39 | 40 | var patternKeys = make(map[string]patternKeyInfo) 41 | 42 | type patternKeyInfo struct { 43 | is, rs, isr, rsi, e bool 44 | } 45 | 46 | func init() { 47 | for _, h := range []HandshakePattern{ 48 | HandshakeNN, 49 | HandshakeKN, 50 | HandshakeNK, 51 | HandshakeKK, 52 | HandshakeNX, 53 | HandshakeKX, 54 | HandshakeXN, 55 | HandshakeIN, 56 | HandshakeXK, 57 | HandshakeIK, 58 | HandshakeXX, 59 | HandshakeIX, 60 | HandshakeN, 61 | HandshakeK, 62 | HandshakeX, 63 | } { 64 | patterns[h.Name] = h 65 | var k patternKeyInfo 66 | if len(h.Name) == 1 { 67 | switch h.Name { 68 | case "N": 69 | k.rs = true 70 | k.rsi = true 71 | case "K": 72 | k.is = true 73 | k.isr = true 74 | k.rs = true 75 | k.rsi = true 76 | case "X": 77 | k.is = true 78 | k.rs = true 79 | k.rsi = true 80 | } 81 | } else { 82 | switch h.Name[0] { 83 | case 'X', 'I': 84 | k.is = true 85 | case 'K': 86 | k.is = true 87 | k.isr = true 88 | } 89 | switch h.Name[1] { 90 | case 'K': 91 | k.rs = true 92 | k.rsi = true 93 | case 'X', 'R': 94 | k.rs = true 95 | } 96 | } 97 | patternKeys[h.Name] = k 98 | } 99 | } 100 | 101 | func (NoiseSuite) TestVectors(c *C) { 102 | f, err := os.Open("vectors.txt") 103 | c.Assert(err, IsNil) 104 | r := bufio.NewReader(f) 105 | 106 | var hsI, hsR *HandshakeState 107 | var staticR, staticI, ephR DHKey 108 | var configI, configR Config 109 | var keyInfo patternKeyInfo 110 | var name string 111 | var payload, psk []byte 112 | var csW0, csW1, csR0, csR1 *CipherState 113 | 114 | for { 115 | line, _, err := r.ReadLine() 116 | if err == io.EOF { 117 | break 118 | } 119 | c.Assert(err, IsNil) 120 | 121 | if len(bytes.TrimSpace(line)) == 0 || line[0] == '#' { 122 | continue 123 | } 124 | 125 | splitLine := bytes.SplitN(line, []byte("="), 2) 126 | c.Assert(splitLine, HasLen, 2) 127 | 128 | switch string(splitLine[0]) { 129 | case "init_static": 130 | staticI, _ = DH25519.GenerateKeypair(hexReader(splitLine[1])) 131 | case "resp_static": 132 | staticR, _ = DH25519.GenerateKeypair(hexReader(splitLine[1])) 133 | case "resp_ephemeral": 134 | ephR, _ = DH25519.GenerateKeypair(hexReader(splitLine[1])) 135 | case "handshake": 136 | name = string(splitLine[1]) 137 | c.Log(name) 138 | configI, configR = Config{Initiator: true}, Config{} 139 | hsI, hsR = nil, nil 140 | components := strings.SplitN(name, "_", 5) 141 | handshakeComponents := strings.Split(components[1], "psk") 142 | if len(handshakeComponents) == 2 { 143 | configI.PresharedKeyPlacement, _ = strconv.Atoi(handshakeComponents[1]) 144 | } 145 | keyInfo = patternKeys[handshakeComponents[0]] 146 | configI.Pattern = patterns[handshakeComponents[0]] 147 | configI.CipherSuite = NewCipherSuite(DH25519, ciphers[components[3]], hashes[components[4]]) 148 | configR.Pattern = configI.Pattern 149 | configR.CipherSuite = configI.CipherSuite 150 | configR.PresharedKeyPlacement = configI.PresharedKeyPlacement 151 | case "gen_init_ephemeral": 152 | configI.Random = hexReader(splitLine[1]) 153 | case "gen_resp_ephemeral": 154 | configR.Random = hexReader(splitLine[1]) 155 | case "prologue": 156 | configI.Prologue = mustHex(splitLine[1]) 157 | configR.Prologue = configI.Prologue 158 | case "preshared_key": 159 | psk = mustHex(splitLine[1]) 160 | } 161 | 162 | if !bytes.HasPrefix(splitLine[0], []byte("msg_")) { 163 | continue 164 | } 165 | if bytes.HasSuffix(splitLine[0], []byte("_payload")) { 166 | payload = mustHex(splitLine[1]) 167 | continue 168 | } 169 | 170 | if hsI == nil { 171 | if keyInfo.is { 172 | configI.StaticKeypair = staticI 173 | } 174 | if keyInfo.rs { 175 | configR.StaticKeypair = staticR 176 | } 177 | if keyInfo.isr { 178 | configR.PeerStatic = staticI.Public 179 | } 180 | if keyInfo.rsi { 181 | configI.PeerStatic = staticR.Public 182 | } 183 | if keyInfo.e { 184 | configR.EphemeralKeypair = ephR 185 | configI.PeerEphemeral = ephR.Public 186 | } 187 | if strings.Contains(name, "psk") { 188 | configI.PresharedKey = psk 189 | configR.PresharedKey = psk 190 | } 191 | hsI, _ = NewHandshakeState(configI) 192 | hsR, _ = NewHandshakeState(configR) 193 | } 194 | 195 | i, _ := strconv.Atoi(string(splitLine[0][4:5])) 196 | 197 | if i > len(configI.Pattern.Messages)-1 { 198 | enc, dec := csW0, csR0 199 | if (i-len(configI.Pattern.Messages))%2 != 0 { 200 | enc, dec = csW1, csR1 201 | } 202 | encrypted, err := enc.Encrypt(nil, nil, payload) 203 | c.Assert(err, IsNil) 204 | c.Assert(fmt.Sprintf("%x", encrypted), Equals, string(splitLine[1])) 205 | decrypted, err := dec.Decrypt(nil, nil, encrypted) 206 | c.Assert(err, IsNil) 207 | c.Assert(string(payload), Equals, string(decrypted)) 208 | payload = nil 209 | continue 210 | } 211 | 212 | writer, reader := hsI, hsR 213 | if i%2 != 0 { 214 | writer, reader = hsR, hsI 215 | } 216 | 217 | var msg, res []byte 218 | msg, csW0, csW1, _ = writer.WriteMessage(nil, payload) 219 | c.Assert(fmt.Sprintf("%x", msg), Equals, string(splitLine[1])) 220 | res, csR0, csR1, err = reader.ReadMessage(nil, msg) 221 | c.Assert(err, IsNil) 222 | c.Assert(string(res), Equals, string(payload)) 223 | payload = nil 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /vectorgen/vectorgen.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "fmt" 7 | "io" 8 | "os" 9 | 10 | . "github.com/flynn/noise" 11 | ) 12 | 13 | func main() { 14 | for _, cipher := range []CipherFunc{CipherAESGCM, CipherChaChaPoly} { 15 | for _, hash := range []HashFunc{HashSHA256, HashSHA512, HashBLAKE2b, HashBLAKE2s} { 16 | for _, handshake := range []HandshakePattern{ 17 | HandshakeNN, 18 | HandshakeKN, 19 | HandshakeNK, 20 | HandshakeKK, 21 | HandshakeNX, 22 | HandshakeKX, 23 | HandshakeXN, 24 | HandshakeIN, 25 | HandshakeXK, 26 | HandshakeIK, 27 | HandshakeXX, 28 | HandshakeIX, 29 | HandshakeN, 30 | HandshakeK, 31 | HandshakeX, 32 | } { 33 | for _, prologue := range []bool{false, true} { 34 | for _, payloads := range []bool{false, true} { 35 | for pskPlacement := -1; pskPlacement <= len(handshake.Messages); pskPlacement++ { 36 | writeHandshake( 37 | os.Stdout, 38 | NewCipherSuite(DH25519, cipher, hash), 39 | handshake, pskPlacement, 40 | pskPlacement >= 0, prologue, payloads, 41 | ) 42 | fmt.Fprintln(os.Stdout) 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | } 50 | 51 | func hexReader(s string) io.Reader { 52 | res, err := hex.DecodeString(s) 53 | if err != nil { 54 | panic(err) 55 | } 56 | return bytes.NewBuffer(res) 57 | } 58 | 59 | const ( 60 | key0 = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" 61 | key1 = "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20" 62 | key2 = "2122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40" 63 | key3 = "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" 64 | key4 = "4142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60" 65 | ) 66 | 67 | func writeHandshake(out io.Writer, cs CipherSuite, h HandshakePattern, pskPlacement int, hasPSK, hasPrologue, payloads bool) { 68 | var prologue, psk []byte 69 | if hasPrologue { 70 | prologue = []byte("notsecret") 71 | } 72 | if hasPSK { 73 | psk = []byte("!verysecretverysecretverysecret!") 74 | } 75 | 76 | staticI, _ := cs.GenerateKeypair(hexReader(key0)) 77 | staticR, _ := cs.GenerateKeypair(hexReader(key1)) 78 | ephR, _ := cs.GenerateKeypair(hexReader(key2)) 79 | 80 | configI := Config{ 81 | CipherSuite: cs, 82 | Random: hexReader(key3), 83 | Pattern: h, 84 | Initiator: true, 85 | Prologue: prologue, 86 | PresharedKey: psk, 87 | PresharedKeyPlacement: pskPlacement, 88 | } 89 | configR := configI 90 | configR.Random = hexReader(key4) 91 | configR.Initiator = false 92 | 93 | var pskName string 94 | if hasPSK { 95 | pskName = fmt.Sprintf("psk%d", pskPlacement) 96 | } 97 | 98 | fmt.Fprintf(out, "handshake=Noise_%s%s_%s\n", h.Name, pskName, cs.Name()) 99 | 100 | if len(h.Name) == 1 { 101 | switch h.Name { 102 | case "N": 103 | configR.StaticKeypair = staticR 104 | configI.PeerStatic = staticR.Public 105 | fmt.Fprintf(out, "resp_static=%x\n", staticR.Private) 106 | case "K": 107 | configI.StaticKeypair = staticI 108 | configR.PeerStatic = staticI.Public 109 | configR.StaticKeypair = staticR 110 | configI.PeerStatic = staticR.Public 111 | fmt.Fprintf(out, "init_static=%x\n", staticI.Private) 112 | fmt.Fprintf(out, "resp_static=%x\n", staticR.Private) 113 | case "X": 114 | configI.StaticKeypair = staticI 115 | configR.StaticKeypair = staticR 116 | configI.PeerStatic = staticR.Public 117 | fmt.Fprintf(out, "init_static=%x\n", staticI.Private) 118 | fmt.Fprintf(out, "resp_static=%x\n", staticR.Private) 119 | } 120 | } else { 121 | switch h.Name[0] { 122 | case 'K', 'X', 'I': 123 | configI.StaticKeypair = staticI 124 | if h.Name[0] == 'K' { 125 | configR.PeerStatic = staticI.Public 126 | } 127 | fmt.Fprintf(out, "init_static=%x\n", staticI.Private) 128 | } 129 | switch h.Name[1] { 130 | case 'K', 'E', 'X', 'R': 131 | configR.StaticKeypair = staticR 132 | fmt.Fprintf(out, "resp_static=%x\n", staticR.Private) 133 | switch h.Name[1] { 134 | case 'K': 135 | configI.PeerStatic = staticR.Public 136 | case 'E': 137 | configR.EphemeralKeypair = ephR 138 | configI.PeerEphemeral = ephR.Public 139 | configI.PeerStatic = staticR.Public 140 | fmt.Fprintf(out, "resp_ephemeral=%x\n", ephR.Private) 141 | } 142 | } 143 | } 144 | 145 | fmt.Fprintf(out, "gen_init_ephemeral=%s\n", key3) 146 | fmt.Fprintf(out, "gen_resp_ephemeral=%s\n", key4) 147 | if len(prologue) > 0 { 148 | fmt.Fprintf(out, "prologue=%x\n", prologue) 149 | } 150 | if len(psk) > 0 { 151 | fmt.Fprintf(out, "preshared_key=%x\n", psk) 152 | } 153 | 154 | hsI, _ := NewHandshakeState(configI) 155 | hsR, _ := NewHandshakeState(configR) 156 | 157 | var cs0, cs1 *CipherState 158 | for i := range h.Messages { 159 | writer, reader := hsI, hsR 160 | if i%2 != 0 { 161 | writer, reader = hsR, hsI 162 | } 163 | 164 | var payload string 165 | if payloads { 166 | payload = fmt.Sprintf("test_msg_%d", i) 167 | } 168 | var msg []byte 169 | msg, cs0, cs1, _ = writer.WriteMessage(nil, []byte(payload)) 170 | _, _, _, err := reader.ReadMessage(nil, msg) 171 | if err != nil { 172 | panic(err) 173 | } 174 | fmt.Fprintf(out, "msg_%d_payload=%x\n", i, payload) 175 | fmt.Fprintf(out, "msg_%d_ciphertext=%x\n", i, msg) 176 | } 177 | 178 | payload0 := []byte("yellowsubmarine") 179 | payload1 := []byte("submarineyellow") 180 | fmt.Fprintf(out, "msg_%d_payload=%x\n", len(h.Messages), payload0) 181 | ciphertext0, _ := cs0.Encrypt(nil, nil, payload0) 182 | fmt.Fprintf(out, "msg_%d_ciphertext=%x\n", len(h.Messages), ciphertext0) 183 | fmt.Fprintf(out, "msg_%d_payload=%x\n", len(h.Messages)+1, payload1) 184 | ciphertext1, _ := cs1.Encrypt(nil, nil, payload1) 185 | fmt.Fprintf(out, "msg_%d_ciphertext=%x\n", len(h.Messages)+1, ciphertext1) 186 | } 187 | --------------------------------------------------------------------------------