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