1// Copyright 2012 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package otr implements the Off The Record protocol as specified in
6// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html
7//
8// The version of OTR implemented by this package has been deprecated
9// (https://bugs.otr.im/lib/libotr/issues/140). An implementation of OTRv3 is
10// available at https://github.com/coyim/otr3.
11package otr // import "golang.org/x/crypto/otr"
12
13import (
14	"bytes"
15	"crypto/aes"
16	"crypto/cipher"
17	"crypto/dsa"
18	"crypto/hmac"
19	"crypto/rand"
20	"crypto/sha1"
21	"crypto/sha256"
22	"crypto/subtle"
23	"encoding/base64"
24	"encoding/hex"
25	"errors"
26	"hash"
27	"io"
28	"math/big"
29	"strconv"
30)
31
32// SecurityChange describes a change in the security state of a Conversation.
33type SecurityChange int
34
35const (
36	NoChange SecurityChange = iota
37	// NewKeys indicates that a key exchange has completed. This occurs
38	// when a conversation first becomes encrypted, and when the keys are
39	// renegotiated within an encrypted conversation.
40	NewKeys
41	// SMPSecretNeeded indicates that the peer has started an
42	// authentication and that we need to supply a secret. Call SMPQuestion
43	// to get the optional, human readable challenge and then Authenticate
44	// to supply the matching secret.
45	SMPSecretNeeded
46	// SMPComplete indicates that an authentication completed. The identity
47	// of the peer has now been confirmed.
48	SMPComplete
49	// SMPFailed indicates that an authentication failed.
50	SMPFailed
51	// ConversationEnded indicates that the peer ended the secure
52	// conversation.
53	ConversationEnded
54)
55
56// QueryMessage can be sent to a peer to start an OTR conversation.
57var QueryMessage = "?OTRv2?"
58
59// ErrorPrefix can be used to make an OTR error by appending an error message
60// to it.
61var ErrorPrefix = "?OTR Error:"
62
63var (
64	fragmentPartSeparator = []byte(",")
65	fragmentPrefix        = []byte("?OTR,")
66	msgPrefix             = []byte("?OTR:")
67	queryMarker           = []byte("?OTR")
68)
69
70// isQuery attempts to parse an OTR query from msg and returns the greatest
71// common version, or 0 if msg is not an OTR query.
72func isQuery(msg []byte) (greatestCommonVersion int) {
73	pos := bytes.Index(msg, queryMarker)
74	if pos == -1 {
75		return 0
76	}
77	for i, c := range msg[pos+len(queryMarker):] {
78		if i == 0 {
79			if c == '?' {
80				// Indicates support for version 1, but we don't
81				// implement that.
82				continue
83			}
84
85			if c != 'v' {
86				// Invalid message
87				return 0
88			}
89
90			continue
91		}
92
93		if c == '?' {
94			// End of message
95			return
96		}
97
98		if c == ' ' || c == '\t' {
99			// Probably an invalid message
100			return 0
101		}
102
103		if c == '2' {
104			greatestCommonVersion = 2
105		}
106	}
107
108	return 0
109}
110
111const (
112	statePlaintext = iota
113	stateEncrypted
114	stateFinished
115)
116
117const (
118	authStateNone = iota
119	authStateAwaitingDHKey
120	authStateAwaitingRevealSig
121	authStateAwaitingSig
122)
123
124const (
125	msgTypeDHCommit  = 2
126	msgTypeData      = 3
127	msgTypeDHKey     = 10
128	msgTypeRevealSig = 17
129	msgTypeSig       = 18
130)
131
132const (
133	// If the requested fragment size is less than this, it will be ignored.
134	minFragmentSize = 18
135	// Messages are padded to a multiple of this number of bytes.
136	paddingGranularity = 256
137	// The number of bytes in a Diffie-Hellman private value (320-bits).
138	dhPrivateBytes = 40
139	// The number of bytes needed to represent an element of the DSA
140	// subgroup (160-bits).
141	dsaSubgroupBytes = 20
142	// The number of bytes of the MAC that are sent on the wire (160-bits).
143	macPrefixBytes = 20
144)
145
146// These are the global, common group parameters for OTR.
147var (
148	p       *big.Int // group prime
149	g       *big.Int // group generator
150	q       *big.Int // group order
151	pMinus2 *big.Int
152)
153
154func init() {
155	p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16)
156	q, _ = new(big.Int).SetString("7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68948127044533E63A0105DF531D89CD9128A5043CC71A026EF7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6F71C35FDAD44CFD2D74F9208BE258FF324943328F6722D9EE1003E5C50B1DF82CC6D241B0E2AE9CD348B1FD47E9267AFC1B2AE91EE51D6CB0E3179AB1042A95DCF6A9483B84B4B36B3861AA7255E4C0278BA36046511B993FFFFFFFFFFFFFFFF", 16)
157	g = new(big.Int).SetInt64(2)
158	pMinus2 = new(big.Int).Sub(p, g)
159}
160
161// Conversation represents a relation with a peer. The zero value is a valid
162// Conversation, although PrivateKey must be set.
163//
164// When communicating with a peer, all inbound messages should be passed to
165// Conversation.Receive and all outbound messages to Conversation.Send. The
166// Conversation will take care of maintaining the encryption state and
167// negotiating encryption as needed.
168type Conversation struct {
169	// PrivateKey contains the private key to use to sign key exchanges.
170	PrivateKey *PrivateKey
171
172	// Rand can be set to override the entropy source. Otherwise,
173	// crypto/rand will be used.
174	Rand io.Reader
175	// If FragmentSize is set, all messages produced by Receive and Send
176	// will be fragmented into messages of, at most, this number of bytes.
177	FragmentSize int
178
179	// Once Receive has returned NewKeys once, the following fields are
180	// valid.
181	SSID           [8]byte
182	TheirPublicKey PublicKey
183
184	state, authState int
185
186	r       [16]byte
187	x, y    *big.Int
188	gx, gy  *big.Int
189	gxBytes []byte
190	digest  [sha256.Size]byte
191
192	revealKeys, sigKeys akeKeys
193
194	myKeyId         uint32
195	myCurrentDHPub  *big.Int
196	myCurrentDHPriv *big.Int
197	myLastDHPub     *big.Int
198	myLastDHPriv    *big.Int
199
200	theirKeyId        uint32
201	theirCurrentDHPub *big.Int
202	theirLastDHPub    *big.Int
203
204	keySlots [4]keySlot
205
206	myCounter    [8]byte
207	theirLastCtr [8]byte
208	oldMACs      []byte
209
210	k, n int // fragment state
211	frag []byte
212
213	smp smpState
214}
215
216// A keySlot contains key material for a specific (their keyid, my keyid) pair.
217type keySlot struct {
218	// used is true if this slot is valid. If false, it's free for reuse.
219	used                   bool
220	theirKeyId             uint32
221	myKeyId                uint32
222	sendAESKey, recvAESKey []byte
223	sendMACKey, recvMACKey []byte
224	theirLastCtr           [8]byte
225}
226
227// akeKeys are generated during key exchange. There's one set for the reveal
228// signature message and another for the signature message. In the protocol
229// spec the latter are indicated with a prime mark.
230type akeKeys struct {
231	c      [16]byte
232	m1, m2 [32]byte
233}
234
235func (c *Conversation) rand() io.Reader {
236	if c.Rand != nil {
237		return c.Rand
238	}
239	return rand.Reader
240}
241
242func (c *Conversation) randMPI(buf []byte) *big.Int {
243	_, err := io.ReadFull(c.rand(), buf)
244	if err != nil {
245		panic("otr: short read from random source")
246	}
247
248	return new(big.Int).SetBytes(buf)
249}
250
251// tlv represents the type-length value from the protocol.
252type tlv struct {
253	typ, length uint16
254	data        []byte
255}
256
257const (
258	tlvTypePadding          = 0
259	tlvTypeDisconnected     = 1
260	tlvTypeSMP1             = 2
261	tlvTypeSMP2             = 3
262	tlvTypeSMP3             = 4
263	tlvTypeSMP4             = 5
264	tlvTypeSMPAbort         = 6
265	tlvTypeSMP1WithQuestion = 7
266)
267
268// Receive handles a message from a peer. It returns a human readable message,
269// an indicator of whether that message was encrypted, a hint about the
270// encryption state and zero or more messages to send back to the peer.
271// These messages do not need to be passed to Send before transmission.
272func (c *Conversation) Receive(in []byte) (out []byte, encrypted bool, change SecurityChange, toSend [][]byte, err error) {
273	if bytes.HasPrefix(in, fragmentPrefix) {
274		in, err = c.processFragment(in)
275		if in == nil || err != nil {
276			return
277		}
278	}
279
280	if bytes.HasPrefix(in, msgPrefix) && in[len(in)-1] == '.' {
281		in = in[len(msgPrefix) : len(in)-1]
282	} else if version := isQuery(in); version > 0 {
283		c.authState = authStateAwaitingDHKey
284		c.reset()
285		toSend = c.encode(c.generateDHCommit())
286		return
287	} else {
288		// plaintext message
289		out = in
290		return
291	}
292
293	msg := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
294	msgLen, err := base64.StdEncoding.Decode(msg, in)
295	if err != nil {
296		err = errors.New("otr: invalid base64 encoding in message")
297		return
298	}
299	msg = msg[:msgLen]
300
301	// The first two bytes are the protocol version (2)
302	if len(msg) < 3 || msg[0] != 0 || msg[1] != 2 {
303		err = errors.New("otr: invalid OTR message")
304		return
305	}
306
307	msgType := int(msg[2])
308	msg = msg[3:]
309
310	switch msgType {
311	case msgTypeDHCommit:
312		switch c.authState {
313		case authStateNone:
314			c.authState = authStateAwaitingRevealSig
315			if err = c.processDHCommit(msg); err != nil {
316				return
317			}
318			c.reset()
319			toSend = c.encode(c.generateDHKey())
320			return
321		case authStateAwaitingDHKey:
322			// This is a 'SYN-crossing'. The greater digest wins.
323			var cmp int
324			if cmp, err = c.compareToDHCommit(msg); err != nil {
325				return
326			}
327			if cmp > 0 {
328				// We win. Retransmit DH commit.
329				toSend = c.encode(c.serializeDHCommit())
330				return
331			} else {
332				// They win. We forget about our DH commit.
333				c.authState = authStateAwaitingRevealSig
334				if err = c.processDHCommit(msg); err != nil {
335					return
336				}
337				c.reset()
338				toSend = c.encode(c.generateDHKey())
339				return
340			}
341		case authStateAwaitingRevealSig:
342			if err = c.processDHCommit(msg); err != nil {
343				return
344			}
345			toSend = c.encode(c.serializeDHKey())
346		case authStateAwaitingSig:
347			if err = c.processDHCommit(msg); err != nil {
348				return
349			}
350			c.reset()
351			toSend = c.encode(c.generateDHKey())
352			c.authState = authStateAwaitingRevealSig
353		default:
354			panic("bad state")
355		}
356	case msgTypeDHKey:
357		switch c.authState {
358		case authStateAwaitingDHKey:
359			var isSame bool
360			if isSame, err = c.processDHKey(msg); err != nil {
361				return
362			}
363			if isSame {
364				err = errors.New("otr: unexpected duplicate DH key")
365				return
366			}
367			toSend = c.encode(c.generateRevealSig())
368			c.authState = authStateAwaitingSig
369		case authStateAwaitingSig:
370			var isSame bool
371			if isSame, err = c.processDHKey(msg); err != nil {
372				return
373			}
374			if isSame {
375				toSend = c.encode(c.serializeDHKey())
376			}
377		}
378	case msgTypeRevealSig:
379		if c.authState != authStateAwaitingRevealSig {
380			return
381		}
382		if err = c.processRevealSig(msg); err != nil {
383			return
384		}
385		toSend = c.encode(c.generateSig())
386		c.authState = authStateNone
387		c.state = stateEncrypted
388		change = NewKeys
389	case msgTypeSig:
390		if c.authState != authStateAwaitingSig {
391			return
392		}
393		if err = c.processSig(msg); err != nil {
394			return
395		}
396		c.authState = authStateNone
397		c.state = stateEncrypted
398		change = NewKeys
399	case msgTypeData:
400		if c.state != stateEncrypted {
401			err = errors.New("otr: encrypted message received without encrypted session established")
402			return
403		}
404		var tlvs []tlv
405		out, tlvs, err = c.processData(msg)
406		encrypted = true
407
408	EachTLV:
409		for _, inTLV := range tlvs {
410			switch inTLV.typ {
411			case tlvTypeDisconnected:
412				change = ConversationEnded
413				c.state = stateFinished
414				break EachTLV
415			case tlvTypeSMP1, tlvTypeSMP2, tlvTypeSMP3, tlvTypeSMP4, tlvTypeSMPAbort, tlvTypeSMP1WithQuestion:
416				var reply tlv
417				var complete bool
418				reply, complete, err = c.processSMP(inTLV)
419				if err == smpSecretMissingError {
420					err = nil
421					change = SMPSecretNeeded
422					c.smp.saved = &inTLV
423					return
424				}
425				if err == smpFailureError {
426					err = nil
427					change = SMPFailed
428				} else if complete {
429					change = SMPComplete
430				}
431				if reply.typ != 0 {
432					toSend = c.encode(c.generateData(nil, &reply))
433				}
434				break EachTLV
435			default:
436				// skip unknown TLVs
437			}
438		}
439	default:
440		err = errors.New("otr: unknown message type " + strconv.Itoa(msgType))
441	}
442
443	return
444}
445
446// Send takes a human readable message from the local user, possibly encrypts
447// it and returns zero one or more messages to send to the peer.
448func (c *Conversation) Send(msg []byte) ([][]byte, error) {
449	switch c.state {
450	case statePlaintext:
451		return [][]byte{msg}, nil
452	case stateEncrypted:
453		return c.encode(c.generateData(msg, nil)), nil
454	case stateFinished:
455		return nil, errors.New("otr: cannot send message because secure conversation has finished")
456	}
457
458	return nil, errors.New("otr: cannot send message in current state")
459}
460
461// SMPQuestion returns the human readable challenge question from the peer.
462// It's only valid after Receive has returned SMPSecretNeeded.
463func (c *Conversation) SMPQuestion() string {
464	return c.smp.question
465}
466
467// Authenticate begins an authentication with the peer. Authentication involves
468// an optional challenge message and a shared secret. The authentication
469// proceeds until either Receive returns SMPComplete, SMPSecretNeeded (which
470// indicates that a new authentication is happening and thus this one was
471// aborted) or SMPFailed.
472func (c *Conversation) Authenticate(question string, mutualSecret []byte) (toSend [][]byte, err error) {
473	if c.state != stateEncrypted {
474		err = errors.New("otr: can't authenticate a peer without a secure conversation established")
475		return
476	}
477
478	if c.smp.saved != nil {
479		c.calcSMPSecret(mutualSecret, false /* they started it */)
480
481		var out tlv
482		var complete bool
483		out, complete, err = c.processSMP(*c.smp.saved)
484		if complete {
485			panic("SMP completed on the first message")
486		}
487		c.smp.saved = nil
488		if out.typ != 0 {
489			toSend = c.encode(c.generateData(nil, &out))
490		}
491		return
492	}
493
494	c.calcSMPSecret(mutualSecret, true /* we started it */)
495	outs := c.startSMP(question)
496	for _, out := range outs {
497		toSend = append(toSend, c.encode(c.generateData(nil, &out))...)
498	}
499	return
500}
501
502// End ends a secure conversation by generating a termination message for
503// the peer and switches to unencrypted communication.
504func (c *Conversation) End() (toSend [][]byte) {
505	switch c.state {
506	case statePlaintext:
507		return nil
508	case stateEncrypted:
509		c.state = statePlaintext
510		return c.encode(c.generateData(nil, &tlv{typ: tlvTypeDisconnected}))
511	case stateFinished:
512		c.state = statePlaintext
513		return nil
514	}
515	panic("unreachable")
516}
517
518// IsEncrypted returns true if a message passed to Send would be encrypted
519// before transmission. This result remains valid until the next call to
520// Receive or End, which may change the state of the Conversation.
521func (c *Conversation) IsEncrypted() bool {
522	return c.state == stateEncrypted
523}
524
525var fragmentError = errors.New("otr: invalid OTR fragment")
526
527// processFragment processes a fragmented OTR message and possibly returns a
528// complete message. Fragmented messages look like "?OTR,k,n,msg," where k is
529// the fragment number (starting from 1), n is the number of fragments in this
530// message and msg is a substring of the base64 encoded message.
531func (c *Conversation) processFragment(in []byte) (out []byte, err error) {
532	in = in[len(fragmentPrefix):] // remove "?OTR,"
533	parts := bytes.Split(in, fragmentPartSeparator)
534	if len(parts) != 4 || len(parts[3]) != 0 {
535		return nil, fragmentError
536	}
537
538	k, err := strconv.Atoi(string(parts[0]))
539	if err != nil {
540		return nil, fragmentError
541	}
542
543	n, err := strconv.Atoi(string(parts[1]))
544	if err != nil {
545		return nil, fragmentError
546	}
547
548	if k < 1 || n < 1 || k > n {
549		return nil, fragmentError
550	}
551
552	if k == 1 {
553		c.frag = append(c.frag[:0], parts[2]...)
554		c.k, c.n = k, n
555	} else if n == c.n && k == c.k+1 {
556		c.frag = append(c.frag, parts[2]...)
557		c.k++
558	} else {
559		c.frag = c.frag[:0]
560		c.n, c.k = 0, 0
561	}
562
563	if c.n > 0 && c.k == c.n {
564		c.n, c.k = 0, 0
565		return c.frag, nil
566	}
567
568	return nil, nil
569}
570
571func (c *Conversation) generateDHCommit() []byte {
572	_, err := io.ReadFull(c.rand(), c.r[:])
573	if err != nil {
574		panic("otr: short read from random source")
575	}
576
577	var xBytes [dhPrivateBytes]byte
578	c.x = c.randMPI(xBytes[:])
579	c.gx = new(big.Int).Exp(g, c.x, p)
580	c.gy = nil
581	c.gxBytes = appendMPI(nil, c.gx)
582
583	h := sha256.New()
584	h.Write(c.gxBytes)
585	h.Sum(c.digest[:0])
586
587	aesCipher, err := aes.NewCipher(c.r[:])
588	if err != nil {
589		panic(err.Error())
590	}
591
592	var iv [aes.BlockSize]byte
593	ctr := cipher.NewCTR(aesCipher, iv[:])
594	ctr.XORKeyStream(c.gxBytes, c.gxBytes)
595
596	return c.serializeDHCommit()
597}
598
599func (c *Conversation) serializeDHCommit() []byte {
600	var ret []byte
601	ret = appendU16(ret, 2) // protocol version
602	ret = append(ret, msgTypeDHCommit)
603	ret = appendData(ret, c.gxBytes)
604	ret = appendData(ret, c.digest[:])
605	return ret
606}
607
608func (c *Conversation) processDHCommit(in []byte) error {
609	var ok1, ok2 bool
610	c.gxBytes, in, ok1 = getData(in)
611	digest, in, ok2 := getData(in)
612	if !ok1 || !ok2 || len(in) > 0 {
613		return errors.New("otr: corrupt DH commit message")
614	}
615	copy(c.digest[:], digest)
616	return nil
617}
618
619func (c *Conversation) compareToDHCommit(in []byte) (int, error) {
620	_, in, ok1 := getData(in)
621	digest, in, ok2 := getData(in)
622	if !ok1 || !ok2 || len(in) > 0 {
623		return 0, errors.New("otr: corrupt DH commit message")
624	}
625	return bytes.Compare(c.digest[:], digest), nil
626}
627
628func (c *Conversation) generateDHKey() []byte {
629	var yBytes [dhPrivateBytes]byte
630	c.y = c.randMPI(yBytes[:])
631	c.gy = new(big.Int).Exp(g, c.y, p)
632	return c.serializeDHKey()
633}
634
635func (c *Conversation) serializeDHKey() []byte {
636	var ret []byte
637	ret = appendU16(ret, 2) // protocol version
638	ret = append(ret, msgTypeDHKey)
639	ret = appendMPI(ret, c.gy)
640	return ret
641}
642
643func (c *Conversation) processDHKey(in []byte) (isSame bool, err error) {
644	gy, _, ok := getMPI(in)
645	if !ok {
646		err = errors.New("otr: corrupt DH key message")
647		return
648	}
649	if gy.Cmp(g) < 0 || gy.Cmp(pMinus2) > 0 {
650		err = errors.New("otr: DH value out of range")
651		return
652	}
653	if c.gy != nil {
654		isSame = c.gy.Cmp(gy) == 0
655		return
656	}
657	c.gy = gy
658	return
659}
660
661func (c *Conversation) generateEncryptedSignature(keys *akeKeys, xFirst bool) ([]byte, []byte) {
662	var xb []byte
663	xb = c.PrivateKey.PublicKey.Serialize(xb)
664
665	var verifyData []byte
666	if xFirst {
667		verifyData = appendMPI(verifyData, c.gx)
668		verifyData = appendMPI(verifyData, c.gy)
669	} else {
670		verifyData = appendMPI(verifyData, c.gy)
671		verifyData = appendMPI(verifyData, c.gx)
672	}
673	verifyData = append(verifyData, xb...)
674	verifyData = appendU32(verifyData, c.myKeyId)
675
676	mac := hmac.New(sha256.New, keys.m1[:])
677	mac.Write(verifyData)
678	mb := mac.Sum(nil)
679
680	xb = appendU32(xb, c.myKeyId)
681	xb = append(xb, c.PrivateKey.Sign(c.rand(), mb)...)
682
683	aesCipher, err := aes.NewCipher(keys.c[:])
684	if err != nil {
685		panic(err.Error())
686	}
687	var iv [aes.BlockSize]byte
688	ctr := cipher.NewCTR(aesCipher, iv[:])
689	ctr.XORKeyStream(xb, xb)
690
691	mac = hmac.New(sha256.New, keys.m2[:])
692	encryptedSig := appendData(nil, xb)
693	mac.Write(encryptedSig)
694
695	return encryptedSig, mac.Sum(nil)
696}
697
698func (c *Conversation) generateRevealSig() []byte {
699	s := new(big.Int).Exp(c.gy, c.x, p)
700	c.calcAKEKeys(s)
701	c.myKeyId++
702
703	encryptedSig, mac := c.generateEncryptedSignature(&c.revealKeys, true /* gx comes first */)
704
705	c.myCurrentDHPub = c.gx
706	c.myCurrentDHPriv = c.x
707	c.rotateDHKeys()
708	incCounter(&c.myCounter)
709
710	var ret []byte
711	ret = appendU16(ret, 2)
712	ret = append(ret, msgTypeRevealSig)
713	ret = appendData(ret, c.r[:])
714	ret = append(ret, encryptedSig...)
715	ret = append(ret, mac[:20]...)
716	return ret
717}
718
719func (c *Conversation) processEncryptedSig(encryptedSig, theirMAC []byte, keys *akeKeys, xFirst bool) error {
720	mac := hmac.New(sha256.New, keys.m2[:])
721	mac.Write(appendData(nil, encryptedSig))
722	myMAC := mac.Sum(nil)[:20]
723
724	if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 {
725		return errors.New("bad signature MAC in encrypted signature")
726	}
727
728	aesCipher, err := aes.NewCipher(keys.c[:])
729	if err != nil {
730		panic(err.Error())
731	}
732	var iv [aes.BlockSize]byte
733	ctr := cipher.NewCTR(aesCipher, iv[:])
734	ctr.XORKeyStream(encryptedSig, encryptedSig)
735
736	sig := encryptedSig
737	sig, ok1 := c.TheirPublicKey.Parse(sig)
738	keyId, sig, ok2 := getU32(sig)
739	if !ok1 || !ok2 {
740		return errors.New("otr: corrupt encrypted signature")
741	}
742
743	var verifyData []byte
744	if xFirst {
745		verifyData = appendMPI(verifyData, c.gx)
746		verifyData = appendMPI(verifyData, c.gy)
747	} else {
748		verifyData = appendMPI(verifyData, c.gy)
749		verifyData = appendMPI(verifyData, c.gx)
750	}
751	verifyData = c.TheirPublicKey.Serialize(verifyData)
752	verifyData = appendU32(verifyData, keyId)
753
754	mac = hmac.New(sha256.New, keys.m1[:])
755	mac.Write(verifyData)
756	mb := mac.Sum(nil)
757
758	sig, ok1 = c.TheirPublicKey.Verify(mb, sig)
759	if !ok1 {
760		return errors.New("bad signature in encrypted signature")
761	}
762	if len(sig) > 0 {
763		return errors.New("corrupt encrypted signature")
764	}
765
766	c.theirKeyId = keyId
767	zero(c.theirLastCtr[:])
768	return nil
769}
770
771func (c *Conversation) processRevealSig(in []byte) error {
772	r, in, ok1 := getData(in)
773	encryptedSig, in, ok2 := getData(in)
774	theirMAC := in
775	if !ok1 || !ok2 || len(theirMAC) != 20 {
776		return errors.New("otr: corrupt reveal signature message")
777	}
778
779	aesCipher, err := aes.NewCipher(r)
780	if err != nil {
781		return errors.New("otr: cannot create AES cipher from reveal signature message: " + err.Error())
782	}
783	var iv [aes.BlockSize]byte
784	ctr := cipher.NewCTR(aesCipher, iv[:])
785	ctr.XORKeyStream(c.gxBytes, c.gxBytes)
786	h := sha256.New()
787	h.Write(c.gxBytes)
788	digest := h.Sum(nil)
789	if len(digest) != len(c.digest) || subtle.ConstantTimeCompare(digest, c.digest[:]) == 0 {
790		return errors.New("otr: bad commit MAC in reveal signature message")
791	}
792	var rest []byte
793	c.gx, rest, ok1 = getMPI(c.gxBytes)
794	if !ok1 || len(rest) > 0 {
795		return errors.New("otr: gx corrupt after decryption")
796	}
797	if c.gx.Cmp(g) < 0 || c.gx.Cmp(pMinus2) > 0 {
798		return errors.New("otr: DH value out of range")
799	}
800	s := new(big.Int).Exp(c.gx, c.y, p)
801	c.calcAKEKeys(s)
802
803	if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.revealKeys, true /* gx comes first */); err != nil {
804		return errors.New("otr: in reveal signature message: " + err.Error())
805	}
806
807	c.theirCurrentDHPub = c.gx
808	c.theirLastDHPub = nil
809
810	return nil
811}
812
813func (c *Conversation) generateSig() []byte {
814	c.myKeyId++
815
816	encryptedSig, mac := c.generateEncryptedSignature(&c.sigKeys, false /* gy comes first */)
817
818	c.myCurrentDHPub = c.gy
819	c.myCurrentDHPriv = c.y
820	c.rotateDHKeys()
821	incCounter(&c.myCounter)
822
823	var ret []byte
824	ret = appendU16(ret, 2)
825	ret = append(ret, msgTypeSig)
826	ret = append(ret, encryptedSig...)
827	ret = append(ret, mac[:macPrefixBytes]...)
828	return ret
829}
830
831func (c *Conversation) processSig(in []byte) error {
832	encryptedSig, in, ok1 := getData(in)
833	theirMAC := in
834	if !ok1 || len(theirMAC) != macPrefixBytes {
835		return errors.New("otr: corrupt signature message")
836	}
837
838	if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.sigKeys, false /* gy comes first */); err != nil {
839		return errors.New("otr: in signature message: " + err.Error())
840	}
841
842	c.theirCurrentDHPub = c.gy
843	c.theirLastDHPub = nil
844
845	return nil
846}
847
848func (c *Conversation) rotateDHKeys() {
849	// evict slots using our retired key id
850	for i := range c.keySlots {
851		slot := &c.keySlots[i]
852		if slot.used && slot.myKeyId == c.myKeyId-1 {
853			slot.used = false
854			c.oldMACs = append(c.oldMACs, slot.recvMACKey...)
855		}
856	}
857
858	c.myLastDHPriv = c.myCurrentDHPriv
859	c.myLastDHPub = c.myCurrentDHPub
860
861	var xBytes [dhPrivateBytes]byte
862	c.myCurrentDHPriv = c.randMPI(xBytes[:])
863	c.myCurrentDHPub = new(big.Int).Exp(g, c.myCurrentDHPriv, p)
864	c.myKeyId++
865}
866
867func (c *Conversation) processData(in []byte) (out []byte, tlvs []tlv, err error) {
868	origIn := in
869	flags, in, ok1 := getU8(in)
870	theirKeyId, in, ok2 := getU32(in)
871	myKeyId, in, ok3 := getU32(in)
872	y, in, ok4 := getMPI(in)
873	counter, in, ok5 := getNBytes(in, 8)
874	encrypted, in, ok6 := getData(in)
875	macedData := origIn[:len(origIn)-len(in)]
876	theirMAC, in, ok7 := getNBytes(in, macPrefixBytes)
877	_, in, ok8 := getData(in)
878	if !ok1 || !ok2 || !ok3 || !ok4 || !ok5 || !ok6 || !ok7 || !ok8 || len(in) > 0 {
879		err = errors.New("otr: corrupt data message")
880		return
881	}
882
883	ignoreErrors := flags&1 != 0
884
885	slot, err := c.calcDataKeys(myKeyId, theirKeyId)
886	if err != nil {
887		if ignoreErrors {
888			err = nil
889		}
890		return
891	}
892
893	mac := hmac.New(sha1.New, slot.recvMACKey)
894	mac.Write([]byte{0, 2, 3})
895	mac.Write(macedData)
896	myMAC := mac.Sum(nil)
897	if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 {
898		if !ignoreErrors {
899			err = errors.New("otr: bad MAC on data message")
900		}
901		return
902	}
903
904	if bytes.Compare(counter, slot.theirLastCtr[:]) <= 0 {
905		err = errors.New("otr: counter regressed")
906		return
907	}
908	copy(slot.theirLastCtr[:], counter)
909
910	var iv [aes.BlockSize]byte
911	copy(iv[:], counter)
912	aesCipher, err := aes.NewCipher(slot.recvAESKey)
913	if err != nil {
914		panic(err.Error())
915	}
916	ctr := cipher.NewCTR(aesCipher, iv[:])
917	ctr.XORKeyStream(encrypted, encrypted)
918	decrypted := encrypted
919
920	if myKeyId == c.myKeyId {
921		c.rotateDHKeys()
922	}
923	if theirKeyId == c.theirKeyId {
924		// evict slots using their retired key id
925		for i := range c.keySlots {
926			slot := &c.keySlots[i]
927			if slot.used && slot.theirKeyId == theirKeyId-1 {
928				slot.used = false
929				c.oldMACs = append(c.oldMACs, slot.recvMACKey...)
930			}
931		}
932
933		c.theirLastDHPub = c.theirCurrentDHPub
934		c.theirKeyId++
935		c.theirCurrentDHPub = y
936	}
937
938	if nulPos := bytes.IndexByte(decrypted, 0); nulPos >= 0 {
939		out = decrypted[:nulPos]
940		tlvData := decrypted[nulPos+1:]
941		for len(tlvData) > 0 {
942			var t tlv
943			var ok1, ok2, ok3 bool
944
945			t.typ, tlvData, ok1 = getU16(tlvData)
946			t.length, tlvData, ok2 = getU16(tlvData)
947			t.data, tlvData, ok3 = getNBytes(tlvData, int(t.length))
948			if !ok1 || !ok2 || !ok3 {
949				err = errors.New("otr: corrupt tlv data")
950				return
951			}
952			tlvs = append(tlvs, t)
953		}
954	} else {
955		out = decrypted
956	}
957
958	return
959}
960
961func (c *Conversation) generateData(msg []byte, extra *tlv) []byte {
962	slot, err := c.calcDataKeys(c.myKeyId-1, c.theirKeyId)
963	if err != nil {
964		panic("otr: failed to generate sending keys: " + err.Error())
965	}
966
967	var plaintext []byte
968	plaintext = append(plaintext, msg...)
969	plaintext = append(plaintext, 0)
970
971	padding := paddingGranularity - ((len(plaintext) + 4) % paddingGranularity)
972	plaintext = appendU16(plaintext, tlvTypePadding)
973	plaintext = appendU16(plaintext, uint16(padding))
974	for i := 0; i < padding; i++ {
975		plaintext = append(plaintext, 0)
976	}
977
978	if extra != nil {
979		plaintext = appendU16(plaintext, extra.typ)
980		plaintext = appendU16(plaintext, uint16(len(extra.data)))
981		plaintext = append(plaintext, extra.data...)
982	}
983
984	encrypted := make([]byte, len(plaintext))
985
986	var iv [aes.BlockSize]byte
987	copy(iv[:], c.myCounter[:])
988	aesCipher, err := aes.NewCipher(slot.sendAESKey)
989	if err != nil {
990		panic(err.Error())
991	}
992	ctr := cipher.NewCTR(aesCipher, iv[:])
993	ctr.XORKeyStream(encrypted, plaintext)
994
995	var ret []byte
996	ret = appendU16(ret, 2)
997	ret = append(ret, msgTypeData)
998	ret = append(ret, 0 /* flags */)
999	ret = appendU32(ret, c.myKeyId-1)
1000	ret = appendU32(ret, c.theirKeyId)
1001	ret = appendMPI(ret, c.myCurrentDHPub)
1002	ret = append(ret, c.myCounter[:]...)
1003	ret = appendData(ret, encrypted)
1004
1005	mac := hmac.New(sha1.New, slot.sendMACKey)
1006	mac.Write(ret)
1007	ret = append(ret, mac.Sum(nil)[:macPrefixBytes]...)
1008	ret = appendData(ret, c.oldMACs)
1009	c.oldMACs = nil
1010	incCounter(&c.myCounter)
1011
1012	return ret
1013}
1014
1015func incCounter(counter *[8]byte) {
1016	for i := 7; i >= 0; i-- {
1017		counter[i]++
1018		if counter[i] > 0 {
1019			break
1020		}
1021	}
1022}
1023
1024// calcDataKeys computes the keys used to encrypt a data message given the key
1025// IDs.
1026func (c *Conversation) calcDataKeys(myKeyId, theirKeyId uint32) (slot *keySlot, err error) {
1027	// Check for a cache hit.
1028	for i := range c.keySlots {
1029		slot = &c.keySlots[i]
1030		if slot.used && slot.theirKeyId == theirKeyId && slot.myKeyId == myKeyId {
1031			return
1032		}
1033	}
1034
1035	// Find an empty slot to write into.
1036	slot = nil
1037	for i := range c.keySlots {
1038		if !c.keySlots[i].used {
1039			slot = &c.keySlots[i]
1040			break
1041		}
1042	}
1043	if slot == nil {
1044		return nil, errors.New("otr: internal error: no more key slots")
1045	}
1046
1047	var myPriv, myPub, theirPub *big.Int
1048
1049	if myKeyId == c.myKeyId {
1050		myPriv = c.myCurrentDHPriv
1051		myPub = c.myCurrentDHPub
1052	} else if myKeyId == c.myKeyId-1 {
1053		myPriv = c.myLastDHPriv
1054		myPub = c.myLastDHPub
1055	} else {
1056		err = errors.New("otr: peer requested keyid " + strconv.FormatUint(uint64(myKeyId), 10) + " when I'm on " + strconv.FormatUint(uint64(c.myKeyId), 10))
1057		return
1058	}
1059
1060	if theirKeyId == c.theirKeyId {
1061		theirPub = c.theirCurrentDHPub
1062	} else if theirKeyId == c.theirKeyId-1 && c.theirLastDHPub != nil {
1063		theirPub = c.theirLastDHPub
1064	} else {
1065		err = errors.New("otr: peer requested keyid " + strconv.FormatUint(uint64(myKeyId), 10) + " when they're on " + strconv.FormatUint(uint64(c.myKeyId), 10))
1066		return
1067	}
1068
1069	var sendPrefixByte, recvPrefixByte [1]byte
1070
1071	if myPub.Cmp(theirPub) > 0 {
1072		// we're the high end
1073		sendPrefixByte[0], recvPrefixByte[0] = 1, 2
1074	} else {
1075		// we're the low end
1076		sendPrefixByte[0], recvPrefixByte[0] = 2, 1
1077	}
1078
1079	s := new(big.Int).Exp(theirPub, myPriv, p)
1080	sBytes := appendMPI(nil, s)
1081
1082	h := sha1.New()
1083	h.Write(sendPrefixByte[:])
1084	h.Write(sBytes)
1085	slot.sendAESKey = h.Sum(slot.sendAESKey[:0])[:16]
1086
1087	h.Reset()
1088	h.Write(slot.sendAESKey)
1089	slot.sendMACKey = h.Sum(slot.sendMACKey[:0])
1090
1091	h.Reset()
1092	h.Write(recvPrefixByte[:])
1093	h.Write(sBytes)
1094	slot.recvAESKey = h.Sum(slot.recvAESKey[:0])[:16]
1095
1096	h.Reset()
1097	h.Write(slot.recvAESKey)
1098	slot.recvMACKey = h.Sum(slot.recvMACKey[:0])
1099
1100	slot.theirKeyId = theirKeyId
1101	slot.myKeyId = myKeyId
1102	slot.used = true
1103
1104	zero(slot.theirLastCtr[:])
1105	return
1106}
1107
1108func (c *Conversation) calcAKEKeys(s *big.Int) {
1109	mpi := appendMPI(nil, s)
1110	h := sha256.New()
1111
1112	var cBytes [32]byte
1113	hashWithPrefix(c.SSID[:], 0, mpi, h)
1114
1115	hashWithPrefix(cBytes[:], 1, mpi, h)
1116	copy(c.revealKeys.c[:], cBytes[:16])
1117	copy(c.sigKeys.c[:], cBytes[16:])
1118
1119	hashWithPrefix(c.revealKeys.m1[:], 2, mpi, h)
1120	hashWithPrefix(c.revealKeys.m2[:], 3, mpi, h)
1121	hashWithPrefix(c.sigKeys.m1[:], 4, mpi, h)
1122	hashWithPrefix(c.sigKeys.m2[:], 5, mpi, h)
1123}
1124
1125func hashWithPrefix(out []byte, prefix byte, in []byte, h hash.Hash) {
1126	h.Reset()
1127	var p [1]byte
1128	p[0] = prefix
1129	h.Write(p[:])
1130	h.Write(in)
1131	if len(out) == h.Size() {
1132		h.Sum(out[:0])
1133	} else {
1134		digest := h.Sum(nil)
1135		copy(out, digest)
1136	}
1137}
1138
1139func (c *Conversation) encode(msg []byte) [][]byte {
1140	b64 := make([]byte, base64.StdEncoding.EncodedLen(len(msg))+len(msgPrefix)+1)
1141	base64.StdEncoding.Encode(b64[len(msgPrefix):], msg)
1142	copy(b64, msgPrefix)
1143	b64[len(b64)-1] = '.'
1144
1145	if c.FragmentSize < minFragmentSize || len(b64) <= c.FragmentSize {
1146		// We can encode this in a single fragment.
1147		return [][]byte{b64}
1148	}
1149
1150	// We have to fragment this message.
1151	var ret [][]byte
1152	bytesPerFragment := c.FragmentSize - minFragmentSize
1153	numFragments := (len(b64) + bytesPerFragment) / bytesPerFragment
1154
1155	for i := 0; i < numFragments; i++ {
1156		frag := []byte("?OTR," + strconv.Itoa(i+1) + "," + strconv.Itoa(numFragments) + ",")
1157		todo := bytesPerFragment
1158		if todo > len(b64) {
1159			todo = len(b64)
1160		}
1161		frag = append(frag, b64[:todo]...)
1162		b64 = b64[todo:]
1163		frag = append(frag, ',')
1164		ret = append(ret, frag)
1165	}
1166
1167	return ret
1168}
1169
1170func (c *Conversation) reset() {
1171	c.myKeyId = 0
1172
1173	for i := range c.keySlots {
1174		c.keySlots[i].used = false
1175	}
1176}
1177
1178type PublicKey struct {
1179	dsa.PublicKey
1180}
1181
1182func (pk *PublicKey) Parse(in []byte) ([]byte, bool) {
1183	var ok bool
1184	var pubKeyType uint16
1185
1186	if pubKeyType, in, ok = getU16(in); !ok || pubKeyType != 0 {
1187		return nil, false
1188	}
1189	if pk.P, in, ok = getMPI(in); !ok {
1190		return nil, false
1191	}
1192	if pk.Q, in, ok = getMPI(in); !ok {
1193		return nil, false
1194	}
1195	if pk.G, in, ok = getMPI(in); !ok {
1196		return nil, false
1197	}
1198	if pk.Y, in, ok = getMPI(in); !ok {
1199		return nil, false
1200	}
1201
1202	return in, true
1203}
1204
1205func (pk *PublicKey) Serialize(in []byte) []byte {
1206	in = appendU16(in, 0)
1207	in = appendMPI(in, pk.P)
1208	in = appendMPI(in, pk.Q)
1209	in = appendMPI(in, pk.G)
1210	in = appendMPI(in, pk.Y)
1211	return in
1212}
1213
1214// Fingerprint returns the 20-byte, binary fingerprint of the PublicKey.
1215func (pk *PublicKey) Fingerprint() []byte {
1216	b := pk.Serialize(nil)
1217	h := sha1.New()
1218	h.Write(b[2:])
1219	return h.Sum(nil)
1220}
1221
1222func (pk *PublicKey) Verify(hashed, sig []byte) ([]byte, bool) {
1223	if len(sig) != 2*dsaSubgroupBytes {
1224		return nil, false
1225	}
1226	r := new(big.Int).SetBytes(sig[:dsaSubgroupBytes])
1227	s := new(big.Int).SetBytes(sig[dsaSubgroupBytes:])
1228	ok := dsa.Verify(&pk.PublicKey, hashed, r, s)
1229	return sig[dsaSubgroupBytes*2:], ok
1230}
1231
1232type PrivateKey struct {
1233	PublicKey
1234	dsa.PrivateKey
1235}
1236
1237func (priv *PrivateKey) Sign(rand io.Reader, hashed []byte) []byte {
1238	r, s, err := dsa.Sign(rand, &priv.PrivateKey, hashed)
1239	if err != nil {
1240		panic(err.Error())
1241	}
1242	rBytes := r.Bytes()
1243	sBytes := s.Bytes()
1244	if len(rBytes) > dsaSubgroupBytes || len(sBytes) > dsaSubgroupBytes {
1245		panic("DSA signature too large")
1246	}
1247
1248	out := make([]byte, 2*dsaSubgroupBytes)
1249	copy(out[dsaSubgroupBytes-len(rBytes):], rBytes)
1250	copy(out[len(out)-len(sBytes):], sBytes)
1251	return out
1252}
1253
1254func (priv *PrivateKey) Serialize(in []byte) []byte {
1255	in = priv.PublicKey.Serialize(in)
1256	in = appendMPI(in, priv.PrivateKey.X)
1257	return in
1258}
1259
1260func (priv *PrivateKey) Parse(in []byte) ([]byte, bool) {
1261	in, ok := priv.PublicKey.Parse(in)
1262	if !ok {
1263		return in, ok
1264	}
1265	priv.PrivateKey.PublicKey = priv.PublicKey.PublicKey
1266	priv.PrivateKey.X, in, ok = getMPI(in)
1267	return in, ok
1268}
1269
1270func (priv *PrivateKey) Generate(rand io.Reader) {
1271	if err := dsa.GenerateParameters(&priv.PrivateKey.PublicKey.Parameters, rand, dsa.L1024N160); err != nil {
1272		panic(err.Error())
1273	}
1274	if err := dsa.GenerateKey(&priv.PrivateKey, rand); err != nil {
1275		panic(err.Error())
1276	}
1277	priv.PublicKey.PublicKey = priv.PrivateKey.PublicKey
1278}
1279
1280func notHex(r rune) bool {
1281	if r >= '0' && r <= '9' ||
1282		r >= 'a' && r <= 'f' ||
1283		r >= 'A' && r <= 'F' {
1284		return false
1285	}
1286
1287	return true
1288}
1289
1290// Import parses the contents of a libotr private key file.
1291func (priv *PrivateKey) Import(in []byte) bool {
1292	mpiStart := []byte(" #")
1293
1294	mpis := make([]*big.Int, 5)
1295
1296	for i := 0; i < len(mpis); i++ {
1297		start := bytes.Index(in, mpiStart)
1298		if start == -1 {
1299			return false
1300		}
1301		in = in[start+len(mpiStart):]
1302		end := bytes.IndexFunc(in, notHex)
1303		if end == -1 {
1304			return false
1305		}
1306		hexBytes := in[:end]
1307		in = in[end:]
1308
1309		if len(hexBytes)&1 != 0 {
1310			return false
1311		}
1312
1313		mpiBytes := make([]byte, len(hexBytes)/2)
1314		if _, err := hex.Decode(mpiBytes, hexBytes); err != nil {
1315			return false
1316		}
1317
1318		mpis[i] = new(big.Int).SetBytes(mpiBytes)
1319	}
1320
1321	for _, mpi := range mpis {
1322		if mpi.Sign() <= 0 {
1323			return false
1324		}
1325	}
1326
1327	priv.PrivateKey.P = mpis[0]
1328	priv.PrivateKey.Q = mpis[1]
1329	priv.PrivateKey.G = mpis[2]
1330	priv.PrivateKey.Y = mpis[3]
1331	priv.PrivateKey.X = mpis[4]
1332	priv.PublicKey.PublicKey = priv.PrivateKey.PublicKey
1333
1334	a := new(big.Int).Exp(priv.PrivateKey.G, priv.PrivateKey.X, priv.PrivateKey.P)
1335	return a.Cmp(priv.PrivateKey.Y) == 0
1336}
1337
1338func getU8(in []byte) (uint8, []byte, bool) {
1339	if len(in) < 1 {
1340		return 0, in, false
1341	}
1342	return in[0], in[1:], true
1343}
1344
1345func getU16(in []byte) (uint16, []byte, bool) {
1346	if len(in) < 2 {
1347		return 0, in, false
1348	}
1349	r := uint16(in[0])<<8 | uint16(in[1])
1350	return r, in[2:], true
1351}
1352
1353func getU32(in []byte) (uint32, []byte, bool) {
1354	if len(in) < 4 {
1355		return 0, in, false
1356	}
1357	r := uint32(in[0])<<24 | uint32(in[1])<<16 | uint32(in[2])<<8 | uint32(in[3])
1358	return r, in[4:], true
1359}
1360
1361func getMPI(in []byte) (*big.Int, []byte, bool) {
1362	l, in, ok := getU32(in)
1363	if !ok || uint32(len(in)) < l {
1364		return nil, in, false
1365	}
1366	r := new(big.Int).SetBytes(in[:l])
1367	return r, in[l:], true
1368}
1369
1370func getData(in []byte) ([]byte, []byte, bool) {
1371	l, in, ok := getU32(in)
1372	if !ok || uint32(len(in)) < l {
1373		return nil, in, false
1374	}
1375	return in[:l], in[l:], true
1376}
1377
1378func getNBytes(in []byte, n int) ([]byte, []byte, bool) {
1379	if len(in) < n {
1380		return nil, in, false
1381	}
1382	return in[:n], in[n:], true
1383}
1384
1385func appendU16(out []byte, v uint16) []byte {
1386	out = append(out, byte(v>>8), byte(v))
1387	return out
1388}
1389
1390func appendU32(out []byte, v uint32) []byte {
1391	out = append(out, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
1392	return out
1393}
1394
1395func appendData(out, v []byte) []byte {
1396	out = appendU32(out, uint32(len(v)))
1397	out = append(out, v...)
1398	return out
1399}
1400
1401func appendMPI(out []byte, v *big.Int) []byte {
1402	vBytes := v.Bytes()
1403	out = appendU32(out, uint32(len(vBytes)))
1404	out = append(out, vBytes...)
1405	return out
1406}
1407
1408func appendMPIs(out []byte, mpis ...*big.Int) []byte {
1409	for _, mpi := range mpis {
1410		out = appendMPI(out, mpi)
1411	}
1412	return out
1413}
1414
1415func zero(b []byte) {
1416	for i := range b {
1417		b[i] = 0
1418	}
1419}
1420