github.com/maenmax/kairep@v0.0.0-20210218001208-55bf3df36788/src/golang.org/x/crypto/otr/otr.go (about) 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 package otr // import "golang.org/x/crypto/otr" 8 9 import ( 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. 29 type SecurityChange int 30 31 const ( 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. 53 var QueryMessage = "?OTRv2?" 54 55 // ErrorPrefix can be used to make an OTR error by appending an error message 56 // to it. 57 var ErrorPrefix = "?OTR Error:" 58 59 var ( 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. 68 func 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 107 const ( 108 statePlaintext = iota 109 stateEncrypted 110 stateFinished 111 ) 112 113 const ( 114 authStateNone = iota 115 authStateAwaitingDHKey 116 authStateAwaitingRevealSig 117 authStateAwaitingSig 118 ) 119 120 const ( 121 msgTypeDHCommit = 2 122 msgTypeData = 3 123 msgTypeDHKey = 10 124 msgTypeRevealSig = 17 125 msgTypeSig = 18 126 ) 127 128 const ( 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. 143 var ( 144 p *big.Int // group prime 145 g *big.Int // group generator 146 q *big.Int // group order 147 pMinus2 *big.Int 148 ) 149 150 func 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. 164 type 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. 213 type 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. 226 type akeKeys struct { 227 c [16]byte 228 m1, m2 [32]byte 229 } 230 231 func (c *Conversation) rand() io.Reader { 232 if c.Rand != nil { 233 return c.Rand 234 } 235 return rand.Reader 236 } 237 238 func (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. 248 type tlv struct { 249 typ, length uint16 250 data []byte 251 } 252 253 const ( 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. 268 func (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 c.reset() 281 toSend = c.encode(c.generateDHCommit()) 282 return 283 } else { 284 // plaintext message 285 out = in 286 return 287 } 288 289 msg := make([]byte, base64.StdEncoding.DecodedLen(len(in))) 290 msgLen, err := base64.StdEncoding.Decode(msg, in) 291 if err != nil { 292 err = errors.New("otr: invalid base64 encoding in message") 293 return 294 } 295 msg = msg[:msgLen] 296 297 // The first two bytes are the protocol version (2) 298 if len(msg) < 3 || msg[0] != 0 || msg[1] != 2 { 299 err = errors.New("otr: invalid OTR message") 300 return 301 } 302 303 msgType := int(msg[2]) 304 msg = msg[3:] 305 306 switch msgType { 307 case msgTypeDHCommit: 308 switch c.authState { 309 case authStateNone: 310 c.authState = authStateAwaitingRevealSig 311 if err = c.processDHCommit(msg); err != nil { 312 return 313 } 314 c.reset() 315 toSend = c.encode(c.generateDHKey()) 316 return 317 case authStateAwaitingDHKey: 318 // This is a 'SYN-crossing'. The greater digest wins. 319 var cmp int 320 if cmp, err = c.compareToDHCommit(msg); err != nil { 321 return 322 } 323 if cmp > 0 { 324 // We win. Retransmit DH commit. 325 toSend = c.encode(c.serializeDHCommit()) 326 return 327 } else { 328 // They win. We forget about our DH commit. 329 c.authState = authStateAwaitingRevealSig 330 if err = c.processDHCommit(msg); err != nil { 331 return 332 } 333 c.reset() 334 toSend = c.encode(c.generateDHKey()) 335 return 336 } 337 case authStateAwaitingRevealSig: 338 if err = c.processDHCommit(msg); err != nil { 339 return 340 } 341 toSend = c.encode(c.serializeDHKey()) 342 case authStateAwaitingSig: 343 if err = c.processDHCommit(msg); err != nil { 344 return 345 } 346 c.reset() 347 toSend = c.encode(c.generateDHKey()) 348 c.authState = authStateAwaitingRevealSig 349 default: 350 panic("bad state") 351 } 352 case msgTypeDHKey: 353 switch c.authState { 354 case authStateAwaitingDHKey: 355 var isSame bool 356 if isSame, err = c.processDHKey(msg); err != nil { 357 return 358 } 359 if isSame { 360 err = errors.New("otr: unexpected duplicate DH key") 361 return 362 } 363 toSend = c.encode(c.generateRevealSig()) 364 c.authState = authStateAwaitingSig 365 case authStateAwaitingSig: 366 var isSame bool 367 if isSame, err = c.processDHKey(msg); err != nil { 368 return 369 } 370 if isSame { 371 toSend = c.encode(c.serializeDHKey()) 372 } 373 } 374 case msgTypeRevealSig: 375 if c.authState != authStateAwaitingRevealSig { 376 return 377 } 378 if err = c.processRevealSig(msg); err != nil { 379 return 380 } 381 toSend = c.encode(c.generateSig()) 382 c.authState = authStateNone 383 c.state = stateEncrypted 384 change = NewKeys 385 case msgTypeSig: 386 if c.authState != authStateAwaitingSig { 387 return 388 } 389 if err = c.processSig(msg); err != nil { 390 return 391 } 392 c.authState = authStateNone 393 c.state = stateEncrypted 394 change = NewKeys 395 case msgTypeData: 396 if c.state != stateEncrypted { 397 err = errors.New("otr: encrypted message received without encrypted session established") 398 return 399 } 400 var tlvs []tlv 401 out, tlvs, err = c.processData(msg) 402 encrypted = true 403 404 EachTLV: 405 for _, inTLV := range tlvs { 406 switch inTLV.typ { 407 case tlvTypeDisconnected: 408 change = ConversationEnded 409 c.state = stateFinished 410 break EachTLV 411 case tlvTypeSMP1, tlvTypeSMP2, tlvTypeSMP3, tlvTypeSMP4, tlvTypeSMPAbort, tlvTypeSMP1WithQuestion: 412 var reply tlv 413 var complete bool 414 reply, complete, err = c.processSMP(inTLV) 415 if err == smpSecretMissingError { 416 err = nil 417 change = SMPSecretNeeded 418 c.smp.saved = &inTLV 419 return 420 } 421 if err == smpFailureError { 422 err = nil 423 change = SMPFailed 424 } else if complete { 425 change = SMPComplete 426 } 427 if reply.typ != 0 { 428 toSend = c.encode(c.generateData(nil, &reply)) 429 } 430 break EachTLV 431 default: 432 // skip unknown TLVs 433 } 434 } 435 default: 436 err = errors.New("otr: unknown message type " + strconv.Itoa(msgType)) 437 } 438 439 return 440 } 441 442 // Send takes a human readable message from the local user, possibly encrypts 443 // it and returns zero one or more messages to send to the peer. 444 func (c *Conversation) Send(msg []byte) ([][]byte, error) { 445 switch c.state { 446 case statePlaintext: 447 return [][]byte{msg}, nil 448 case stateEncrypted: 449 return c.encode(c.generateData(msg, nil)), nil 450 case stateFinished: 451 return nil, errors.New("otr: cannot send message because secure conversation has finished") 452 } 453 454 return nil, errors.New("otr: cannot send message in current state") 455 } 456 457 // SMPQuestion returns the human readable challenge question from the peer. 458 // It's only valid after Receive has returned SMPSecretNeeded. 459 func (c *Conversation) SMPQuestion() string { 460 return c.smp.question 461 } 462 463 // Authenticate begins an authentication with the peer. Authentication involves 464 // an optional challenge message and a shared secret. The authentication 465 // proceeds until either Receive returns SMPComplete, SMPSecretNeeded (which 466 // indicates that a new authentication is happening and thus this one was 467 // aborted) or SMPFailed. 468 func (c *Conversation) Authenticate(question string, mutualSecret []byte) (toSend [][]byte, err error) { 469 if c.state != stateEncrypted { 470 err = errors.New("otr: can't authenticate a peer without a secure conversation established") 471 return 472 } 473 474 if c.smp.saved != nil { 475 c.calcSMPSecret(mutualSecret, false /* they started it */) 476 477 var out tlv 478 var complete bool 479 out, complete, err = c.processSMP(*c.smp.saved) 480 if complete { 481 panic("SMP completed on the first message") 482 } 483 c.smp.saved = nil 484 if out.typ != 0 { 485 toSend = c.encode(c.generateData(nil, &out)) 486 } 487 return 488 } 489 490 c.calcSMPSecret(mutualSecret, true /* we started it */) 491 outs := c.startSMP(question) 492 for _, out := range outs { 493 toSend = append(toSend, c.encode(c.generateData(nil, &out))...) 494 } 495 return 496 } 497 498 // End ends a secure conversation by generating a termination message for 499 // the peer and switches to unencrypted communication. 500 func (c *Conversation) End() (toSend [][]byte) { 501 switch c.state { 502 case statePlaintext: 503 return nil 504 case stateEncrypted: 505 c.state = statePlaintext 506 return c.encode(c.generateData(nil, &tlv{typ: tlvTypeDisconnected})) 507 case stateFinished: 508 c.state = statePlaintext 509 return nil 510 } 511 panic("unreachable") 512 } 513 514 // IsEncrypted returns true if a message passed to Send would be encrypted 515 // before transmission. This result remains valid until the next call to 516 // Receive or End, which may change the state of the Conversation. 517 func (c *Conversation) IsEncrypted() bool { 518 return c.state == stateEncrypted 519 } 520 521 var fragmentError = errors.New("otr: invalid OTR fragment") 522 523 // processFragment processes a fragmented OTR message and possibly returns a 524 // complete message. Fragmented messages look like "?OTR,k,n,msg," where k is 525 // the fragment number (starting from 1), n is the number of fragments in this 526 // message and msg is a substring of the base64 encoded message. 527 func (c *Conversation) processFragment(in []byte) (out []byte, err error) { 528 in = in[len(fragmentPrefix):] // remove "?OTR," 529 parts := bytes.Split(in, fragmentPartSeparator) 530 if len(parts) != 4 || len(parts[3]) != 0 { 531 return nil, fragmentError 532 } 533 534 k, err := strconv.Atoi(string(parts[0])) 535 if err != nil { 536 return nil, fragmentError 537 } 538 539 n, err := strconv.Atoi(string(parts[1])) 540 if err != nil { 541 return nil, fragmentError 542 } 543 544 if k < 1 || n < 1 || k > n { 545 return nil, fragmentError 546 } 547 548 if k == 1 { 549 c.frag = append(c.frag[:0], parts[2]...) 550 c.k, c.n = k, n 551 } else if n == c.n && k == c.k+1 { 552 c.frag = append(c.frag, parts[2]...) 553 c.k++ 554 } else { 555 c.frag = c.frag[:0] 556 c.n, c.k = 0, 0 557 } 558 559 if c.n > 0 && c.k == c.n { 560 c.n, c.k = 0, 0 561 return c.frag, nil 562 } 563 564 return nil, nil 565 } 566 567 func (c *Conversation) generateDHCommit() []byte { 568 _, err := io.ReadFull(c.rand(), c.r[:]) 569 if err != nil { 570 panic("otr: short read from random source") 571 } 572 573 var xBytes [dhPrivateBytes]byte 574 c.x = c.randMPI(xBytes[:]) 575 c.gx = new(big.Int).Exp(g, c.x, p) 576 c.gy = nil 577 c.gxBytes = appendMPI(nil, c.gx) 578 579 h := sha256.New() 580 h.Write(c.gxBytes) 581 h.Sum(c.digest[:0]) 582 583 aesCipher, err := aes.NewCipher(c.r[:]) 584 if err != nil { 585 panic(err.Error()) 586 } 587 588 var iv [aes.BlockSize]byte 589 ctr := cipher.NewCTR(aesCipher, iv[:]) 590 ctr.XORKeyStream(c.gxBytes, c.gxBytes) 591 592 return c.serializeDHCommit() 593 } 594 595 func (c *Conversation) serializeDHCommit() []byte { 596 var ret []byte 597 ret = appendU16(ret, 2) // protocol version 598 ret = append(ret, msgTypeDHCommit) 599 ret = appendData(ret, c.gxBytes) 600 ret = appendData(ret, c.digest[:]) 601 return ret 602 } 603 604 func (c *Conversation) processDHCommit(in []byte) error { 605 var ok1, ok2 bool 606 c.gxBytes, in, ok1 = getData(in) 607 digest, in, ok2 := getData(in) 608 if !ok1 || !ok2 || len(in) > 0 { 609 return errors.New("otr: corrupt DH commit message") 610 } 611 copy(c.digest[:], digest) 612 return nil 613 } 614 615 func (c *Conversation) compareToDHCommit(in []byte) (int, error) { 616 _, in, ok1 := getData(in) 617 digest, in, ok2 := getData(in) 618 if !ok1 || !ok2 || len(in) > 0 { 619 return 0, errors.New("otr: corrupt DH commit message") 620 } 621 return bytes.Compare(c.digest[:], digest), nil 622 } 623 624 func (c *Conversation) generateDHKey() []byte { 625 var yBytes [dhPrivateBytes]byte 626 c.y = c.randMPI(yBytes[:]) 627 c.gy = new(big.Int).Exp(g, c.y, p) 628 return c.serializeDHKey() 629 } 630 631 func (c *Conversation) serializeDHKey() []byte { 632 var ret []byte 633 ret = appendU16(ret, 2) // protocol version 634 ret = append(ret, msgTypeDHKey) 635 ret = appendMPI(ret, c.gy) 636 return ret 637 } 638 639 func (c *Conversation) processDHKey(in []byte) (isSame bool, err error) { 640 gy, in, ok := getMPI(in) 641 if !ok { 642 err = errors.New("otr: corrupt DH key message") 643 return 644 } 645 if gy.Cmp(g) < 0 || gy.Cmp(pMinus2) > 0 { 646 err = errors.New("otr: DH value out of range") 647 return 648 } 649 if c.gy != nil { 650 isSame = c.gy.Cmp(gy) == 0 651 return 652 } 653 c.gy = gy 654 return 655 } 656 657 func (c *Conversation) generateEncryptedSignature(keys *akeKeys, xFirst bool) ([]byte, []byte) { 658 var xb []byte 659 xb = c.PrivateKey.PublicKey.Serialize(xb) 660 661 var verifyData []byte 662 if xFirst { 663 verifyData = appendMPI(verifyData, c.gx) 664 verifyData = appendMPI(verifyData, c.gy) 665 } else { 666 verifyData = appendMPI(verifyData, c.gy) 667 verifyData = appendMPI(verifyData, c.gx) 668 } 669 verifyData = append(verifyData, xb...) 670 verifyData = appendU32(verifyData, c.myKeyId) 671 672 mac := hmac.New(sha256.New, keys.m1[:]) 673 mac.Write(verifyData) 674 mb := mac.Sum(nil) 675 676 xb = appendU32(xb, c.myKeyId) 677 xb = append(xb, c.PrivateKey.Sign(c.rand(), mb)...) 678 679 aesCipher, err := aes.NewCipher(keys.c[:]) 680 if err != nil { 681 panic(err.Error()) 682 } 683 var iv [aes.BlockSize]byte 684 ctr := cipher.NewCTR(aesCipher, iv[:]) 685 ctr.XORKeyStream(xb, xb) 686 687 mac = hmac.New(sha256.New, keys.m2[:]) 688 encryptedSig := appendData(nil, xb) 689 mac.Write(encryptedSig) 690 691 return encryptedSig, mac.Sum(nil) 692 } 693 694 func (c *Conversation) generateRevealSig() []byte { 695 s := new(big.Int).Exp(c.gy, c.x, p) 696 c.calcAKEKeys(s) 697 c.myKeyId++ 698 699 encryptedSig, mac := c.generateEncryptedSignature(&c.revealKeys, true /* gx comes first */) 700 701 c.myCurrentDHPub = c.gx 702 c.myCurrentDHPriv = c.x 703 c.rotateDHKeys() 704 incCounter(&c.myCounter) 705 706 var ret []byte 707 ret = appendU16(ret, 2) 708 ret = append(ret, msgTypeRevealSig) 709 ret = appendData(ret, c.r[:]) 710 ret = append(ret, encryptedSig...) 711 ret = append(ret, mac[:20]...) 712 return ret 713 } 714 715 func (c *Conversation) processEncryptedSig(encryptedSig, theirMAC []byte, keys *akeKeys, xFirst bool) error { 716 mac := hmac.New(sha256.New, keys.m2[:]) 717 mac.Write(appendData(nil, encryptedSig)) 718 myMAC := mac.Sum(nil)[:20] 719 720 if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 { 721 return errors.New("bad signature MAC in encrypted signature") 722 } 723 724 aesCipher, err := aes.NewCipher(keys.c[:]) 725 if err != nil { 726 panic(err.Error()) 727 } 728 var iv [aes.BlockSize]byte 729 ctr := cipher.NewCTR(aesCipher, iv[:]) 730 ctr.XORKeyStream(encryptedSig, encryptedSig) 731 732 sig := encryptedSig 733 sig, ok1 := c.TheirPublicKey.Parse(sig) 734 keyId, sig, ok2 := getU32(sig) 735 if !ok1 || !ok2 { 736 return errors.New("otr: corrupt encrypted signature") 737 } 738 739 var verifyData []byte 740 if xFirst { 741 verifyData = appendMPI(verifyData, c.gx) 742 verifyData = appendMPI(verifyData, c.gy) 743 } else { 744 verifyData = appendMPI(verifyData, c.gy) 745 verifyData = appendMPI(verifyData, c.gx) 746 } 747 verifyData = c.TheirPublicKey.Serialize(verifyData) 748 verifyData = appendU32(verifyData, keyId) 749 750 mac = hmac.New(sha256.New, keys.m1[:]) 751 mac.Write(verifyData) 752 mb := mac.Sum(nil) 753 754 sig, ok1 = c.TheirPublicKey.Verify(mb, sig) 755 if !ok1 { 756 return errors.New("bad signature in encrypted signature") 757 } 758 if len(sig) > 0 { 759 return errors.New("corrupt encrypted signature") 760 } 761 762 c.theirKeyId = keyId 763 zero(c.theirLastCtr[:]) 764 return nil 765 } 766 767 func (c *Conversation) processRevealSig(in []byte) error { 768 r, in, ok1 := getData(in) 769 encryptedSig, in, ok2 := getData(in) 770 theirMAC := in 771 if !ok1 || !ok2 || len(theirMAC) != 20 { 772 return errors.New("otr: corrupt reveal signature message") 773 } 774 775 aesCipher, err := aes.NewCipher(r) 776 if err != nil { 777 return errors.New("otr: cannot create AES cipher from reveal signature message: " + err.Error()) 778 } 779 var iv [aes.BlockSize]byte 780 ctr := cipher.NewCTR(aesCipher, iv[:]) 781 ctr.XORKeyStream(c.gxBytes, c.gxBytes) 782 h := sha256.New() 783 h.Write(c.gxBytes) 784 digest := h.Sum(nil) 785 if len(digest) != len(c.digest) || subtle.ConstantTimeCompare(digest, c.digest[:]) == 0 { 786 return errors.New("otr: bad commit MAC in reveal signature message") 787 } 788 var rest []byte 789 c.gx, rest, ok1 = getMPI(c.gxBytes) 790 if !ok1 || len(rest) > 0 { 791 return errors.New("otr: gx corrupt after decryption") 792 } 793 if c.gx.Cmp(g) < 0 || c.gx.Cmp(pMinus2) > 0 { 794 return errors.New("otr: DH value out of range") 795 } 796 s := new(big.Int).Exp(c.gx, c.y, p) 797 c.calcAKEKeys(s) 798 799 if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.revealKeys, true /* gx comes first */); err != nil { 800 return errors.New("otr: in reveal signature message: " + err.Error()) 801 } 802 803 c.theirCurrentDHPub = c.gx 804 c.theirLastDHPub = nil 805 806 return nil 807 } 808 809 func (c *Conversation) generateSig() []byte { 810 c.myKeyId++ 811 812 encryptedSig, mac := c.generateEncryptedSignature(&c.sigKeys, false /* gy comes first */) 813 814 c.myCurrentDHPub = c.gy 815 c.myCurrentDHPriv = c.y 816 c.rotateDHKeys() 817 incCounter(&c.myCounter) 818 819 var ret []byte 820 ret = appendU16(ret, 2) 821 ret = append(ret, msgTypeSig) 822 ret = append(ret, encryptedSig...) 823 ret = append(ret, mac[:macPrefixBytes]...) 824 return ret 825 } 826 827 func (c *Conversation) processSig(in []byte) error { 828 encryptedSig, in, ok1 := getData(in) 829 theirMAC := in 830 if !ok1 || len(theirMAC) != macPrefixBytes { 831 return errors.New("otr: corrupt signature message") 832 } 833 834 if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.sigKeys, false /* gy comes first */); err != nil { 835 return errors.New("otr: in signature message: " + err.Error()) 836 } 837 838 c.theirCurrentDHPub = c.gy 839 c.theirLastDHPub = nil 840 841 return nil 842 } 843 844 func (c *Conversation) rotateDHKeys() { 845 // evict slots using our retired key id 846 for i := range c.keySlots { 847 slot := &c.keySlots[i] 848 if slot.used && slot.myKeyId == c.myKeyId-1 { 849 slot.used = false 850 c.oldMACs = append(c.oldMACs, slot.recvMACKey...) 851 } 852 } 853 854 c.myLastDHPriv = c.myCurrentDHPriv 855 c.myLastDHPub = c.myCurrentDHPub 856 857 var xBytes [dhPrivateBytes]byte 858 c.myCurrentDHPriv = c.randMPI(xBytes[:]) 859 c.myCurrentDHPub = new(big.Int).Exp(g, c.myCurrentDHPriv, p) 860 c.myKeyId++ 861 } 862 863 func (c *Conversation) processData(in []byte) (out []byte, tlvs []tlv, err error) { 864 origIn := in 865 flags, in, ok1 := getU8(in) 866 theirKeyId, in, ok2 := getU32(in) 867 myKeyId, in, ok3 := getU32(in) 868 y, in, ok4 := getMPI(in) 869 counter, in, ok5 := getNBytes(in, 8) 870 encrypted, in, ok6 := getData(in) 871 macedData := origIn[:len(origIn)-len(in)] 872 theirMAC, in, ok7 := getNBytes(in, macPrefixBytes) 873 _, in, ok8 := getData(in) 874 if !ok1 || !ok2 || !ok3 || !ok4 || !ok5 || !ok6 || !ok7 || !ok8 || len(in) > 0 { 875 err = errors.New("otr: corrupt data message") 876 return 877 } 878 879 ignoreErrors := flags&1 != 0 880 881 slot, err := c.calcDataKeys(myKeyId, theirKeyId) 882 if err != nil { 883 if ignoreErrors { 884 err = nil 885 } 886 return 887 } 888 889 mac := hmac.New(sha1.New, slot.recvMACKey) 890 mac.Write([]byte{0, 2, 3}) 891 mac.Write(macedData) 892 myMAC := mac.Sum(nil) 893 if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 { 894 if !ignoreErrors { 895 err = errors.New("otr: bad MAC on data message") 896 } 897 return 898 } 899 900 if bytes.Compare(counter, slot.theirLastCtr[:]) <= 0 { 901 err = errors.New("otr: counter regressed") 902 return 903 } 904 copy(slot.theirLastCtr[:], counter) 905 906 var iv [aes.BlockSize]byte 907 copy(iv[:], counter) 908 aesCipher, err := aes.NewCipher(slot.recvAESKey) 909 if err != nil { 910 panic(err.Error()) 911 } 912 ctr := cipher.NewCTR(aesCipher, iv[:]) 913 ctr.XORKeyStream(encrypted, encrypted) 914 decrypted := encrypted 915 916 if myKeyId == c.myKeyId { 917 c.rotateDHKeys() 918 } 919 if theirKeyId == c.theirKeyId { 920 // evict slots using their retired key id 921 for i := range c.keySlots { 922 slot := &c.keySlots[i] 923 if slot.used && slot.theirKeyId == theirKeyId-1 { 924 slot.used = false 925 c.oldMACs = append(c.oldMACs, slot.recvMACKey...) 926 } 927 } 928 929 c.theirLastDHPub = c.theirCurrentDHPub 930 c.theirKeyId++ 931 c.theirCurrentDHPub = y 932 } 933 934 if nulPos := bytes.IndexByte(decrypted, 0); nulPos >= 0 { 935 out = decrypted[:nulPos] 936 tlvData := decrypted[nulPos+1:] 937 for len(tlvData) > 0 { 938 var t tlv 939 var ok1, ok2, ok3 bool 940 941 t.typ, tlvData, ok1 = getU16(tlvData) 942 t.length, tlvData, ok2 = getU16(tlvData) 943 t.data, tlvData, ok3 = getNBytes(tlvData, int(t.length)) 944 if !ok1 || !ok2 || !ok3 { 945 err = errors.New("otr: corrupt tlv data") 946 } 947 tlvs = append(tlvs, t) 948 } 949 } else { 950 out = decrypted 951 } 952 953 return 954 } 955 956 func (c *Conversation) generateData(msg []byte, extra *tlv) []byte { 957 slot, err := c.calcDataKeys(c.myKeyId-1, c.theirKeyId) 958 if err != nil { 959 panic("otr: failed to generate sending keys: " + err.Error()) 960 } 961 962 var plaintext []byte 963 plaintext = append(plaintext, msg...) 964 plaintext = append(plaintext, 0) 965 966 padding := paddingGranularity - ((len(plaintext) + 4) % paddingGranularity) 967 plaintext = appendU16(plaintext, tlvTypePadding) 968 plaintext = appendU16(plaintext, uint16(padding)) 969 for i := 0; i < padding; i++ { 970 plaintext = append(plaintext, 0) 971 } 972 973 if extra != nil { 974 plaintext = appendU16(plaintext, extra.typ) 975 plaintext = appendU16(plaintext, uint16(len(extra.data))) 976 plaintext = append(plaintext, extra.data...) 977 } 978 979 encrypted := make([]byte, len(plaintext)) 980 981 var iv [aes.BlockSize]byte 982 copy(iv[:], c.myCounter[:]) 983 aesCipher, err := aes.NewCipher(slot.sendAESKey) 984 if err != nil { 985 panic(err.Error()) 986 } 987 ctr := cipher.NewCTR(aesCipher, iv[:]) 988 ctr.XORKeyStream(encrypted, plaintext) 989 990 var ret []byte 991 ret = appendU16(ret, 2) 992 ret = append(ret, msgTypeData) 993 ret = append(ret, 0 /* flags */) 994 ret = appendU32(ret, c.myKeyId-1) 995 ret = appendU32(ret, c.theirKeyId) 996 ret = appendMPI(ret, c.myCurrentDHPub) 997 ret = append(ret, c.myCounter[:]...) 998 ret = appendData(ret, encrypted) 999 1000 mac := hmac.New(sha1.New, slot.sendMACKey) 1001 mac.Write(ret) 1002 ret = append(ret, mac.Sum(nil)[:macPrefixBytes]...) 1003 ret = appendData(ret, c.oldMACs) 1004 c.oldMACs = nil 1005 incCounter(&c.myCounter) 1006 1007 return ret 1008 } 1009 1010 func incCounter(counter *[8]byte) { 1011 for i := 7; i >= 0; i-- { 1012 counter[i]++ 1013 if counter[i] > 0 { 1014 break 1015 } 1016 } 1017 } 1018 1019 // calcDataKeys computes the keys used to encrypt a data message given the key 1020 // IDs. 1021 func (c *Conversation) calcDataKeys(myKeyId, theirKeyId uint32) (slot *keySlot, err error) { 1022 // Check for a cache hit. 1023 for i := range c.keySlots { 1024 slot = &c.keySlots[i] 1025 if slot.used && slot.theirKeyId == theirKeyId && slot.myKeyId == myKeyId { 1026 return 1027 } 1028 } 1029 1030 // Find an empty slot to write into. 1031 slot = nil 1032 for i := range c.keySlots { 1033 if !c.keySlots[i].used { 1034 slot = &c.keySlots[i] 1035 break 1036 } 1037 } 1038 if slot == nil { 1039 return nil, errors.New("otr: internal error: no more key slots") 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 slot.theirKeyId = theirKeyId 1096 slot.myKeyId = myKeyId 1097 slot.used = true 1098 1099 zero(slot.theirLastCtr[:]) 1100 return 1101 } 1102 1103 func (c *Conversation) calcAKEKeys(s *big.Int) { 1104 mpi := appendMPI(nil, s) 1105 h := sha256.New() 1106 1107 var cBytes [32]byte 1108 hashWithPrefix(c.SSID[:], 0, mpi, h) 1109 1110 hashWithPrefix(cBytes[:], 1, mpi, h) 1111 copy(c.revealKeys.c[:], cBytes[:16]) 1112 copy(c.sigKeys.c[:], cBytes[16:]) 1113 1114 hashWithPrefix(c.revealKeys.m1[:], 2, mpi, h) 1115 hashWithPrefix(c.revealKeys.m2[:], 3, mpi, h) 1116 hashWithPrefix(c.sigKeys.m1[:], 4, mpi, h) 1117 hashWithPrefix(c.sigKeys.m2[:], 5, mpi, h) 1118 } 1119 1120 func hashWithPrefix(out []byte, prefix byte, in []byte, h hash.Hash) { 1121 h.Reset() 1122 var p [1]byte 1123 p[0] = prefix 1124 h.Write(p[:]) 1125 h.Write(in) 1126 if len(out) == h.Size() { 1127 h.Sum(out[:0]) 1128 } else { 1129 digest := h.Sum(nil) 1130 copy(out, digest) 1131 } 1132 } 1133 1134 func (c *Conversation) encode(msg []byte) [][]byte { 1135 b64 := make([]byte, base64.StdEncoding.EncodedLen(len(msg))+len(msgPrefix)+1) 1136 base64.StdEncoding.Encode(b64[len(msgPrefix):], msg) 1137 copy(b64, msgPrefix) 1138 b64[len(b64)-1] = '.' 1139 1140 if c.FragmentSize < minFragmentSize || len(b64) <= c.FragmentSize { 1141 // We can encode this in a single fragment. 1142 return [][]byte{b64} 1143 } 1144 1145 // We have to fragment this message. 1146 var ret [][]byte 1147 bytesPerFragment := c.FragmentSize - minFragmentSize 1148 numFragments := (len(b64) + bytesPerFragment) / bytesPerFragment 1149 1150 for i := 0; i < numFragments; i++ { 1151 frag := []byte("?OTR," + strconv.Itoa(i+1) + "," + strconv.Itoa(numFragments) + ",") 1152 todo := bytesPerFragment 1153 if todo > len(b64) { 1154 todo = len(b64) 1155 } 1156 frag = append(frag, b64[:todo]...) 1157 b64 = b64[todo:] 1158 frag = append(frag, ',') 1159 ret = append(ret, frag) 1160 } 1161 1162 return ret 1163 } 1164 1165 func (c *Conversation) reset() { 1166 c.myKeyId = 0 1167 1168 for i := range c.keySlots { 1169 c.keySlots[i].used = false 1170 } 1171 } 1172 1173 type PublicKey struct { 1174 dsa.PublicKey 1175 } 1176 1177 func (pk *PublicKey) Parse(in []byte) ([]byte, bool) { 1178 var ok bool 1179 var pubKeyType uint16 1180 1181 if pubKeyType, in, ok = getU16(in); !ok || pubKeyType != 0 { 1182 return nil, false 1183 } 1184 if pk.P, in, ok = getMPI(in); !ok { 1185 return nil, false 1186 } 1187 if pk.Q, in, ok = getMPI(in); !ok { 1188 return nil, false 1189 } 1190 if pk.G, in, ok = getMPI(in); !ok { 1191 return nil, false 1192 } 1193 if pk.Y, in, ok = getMPI(in); !ok { 1194 return nil, false 1195 } 1196 1197 return in, true 1198 } 1199 1200 func (pk *PublicKey) Serialize(in []byte) []byte { 1201 in = appendU16(in, 0) 1202 in = appendMPI(in, pk.P) 1203 in = appendMPI(in, pk.Q) 1204 in = appendMPI(in, pk.G) 1205 in = appendMPI(in, pk.Y) 1206 return in 1207 } 1208 1209 // Fingerprint returns the 20-byte, binary fingerprint of the PublicKey. 1210 func (pk *PublicKey) Fingerprint() []byte { 1211 b := pk.Serialize(nil) 1212 h := sha1.New() 1213 h.Write(b[2:]) 1214 return h.Sum(nil) 1215 } 1216 1217 func (pk *PublicKey) Verify(hashed, sig []byte) ([]byte, bool) { 1218 if len(sig) != 2*dsaSubgroupBytes { 1219 return nil, false 1220 } 1221 r := new(big.Int).SetBytes(sig[:dsaSubgroupBytes]) 1222 s := new(big.Int).SetBytes(sig[dsaSubgroupBytes:]) 1223 ok := dsa.Verify(&pk.PublicKey, hashed, r, s) 1224 return sig[dsaSubgroupBytes*2:], ok 1225 } 1226 1227 type PrivateKey struct { 1228 PublicKey 1229 dsa.PrivateKey 1230 } 1231 1232 func (priv *PrivateKey) Sign(rand io.Reader, hashed []byte) []byte { 1233 r, s, err := dsa.Sign(rand, &priv.PrivateKey, hashed) 1234 if err != nil { 1235 panic(err.Error()) 1236 } 1237 rBytes := r.Bytes() 1238 sBytes := s.Bytes() 1239 if len(rBytes) > dsaSubgroupBytes || len(sBytes) > dsaSubgroupBytes { 1240 panic("DSA signature too large") 1241 } 1242 1243 out := make([]byte, 2*dsaSubgroupBytes) 1244 copy(out[dsaSubgroupBytes-len(rBytes):], rBytes) 1245 copy(out[len(out)-len(sBytes):], sBytes) 1246 return out 1247 } 1248 1249 func (priv *PrivateKey) Serialize(in []byte) []byte { 1250 in = priv.PublicKey.Serialize(in) 1251 in = appendMPI(in, priv.PrivateKey.X) 1252 return in 1253 } 1254 1255 func (priv *PrivateKey) Parse(in []byte) ([]byte, bool) { 1256 in, ok := priv.PublicKey.Parse(in) 1257 if !ok { 1258 return in, ok 1259 } 1260 priv.PrivateKey.PublicKey = priv.PublicKey.PublicKey 1261 priv.PrivateKey.X, in, ok = getMPI(in) 1262 return in, ok 1263 } 1264 1265 func (priv *PrivateKey) Generate(rand io.Reader) { 1266 if err := dsa.GenerateParameters(&priv.PrivateKey.PublicKey.Parameters, rand, dsa.L1024N160); err != nil { 1267 panic(err.Error()) 1268 } 1269 if err := dsa.GenerateKey(&priv.PrivateKey, rand); err != nil { 1270 panic(err.Error()) 1271 } 1272 priv.PublicKey.PublicKey = priv.PrivateKey.PublicKey 1273 } 1274 1275 func notHex(r rune) bool { 1276 if r >= '0' && r <= '9' || 1277 r >= 'a' && r <= 'f' || 1278 r >= 'A' && r <= 'F' { 1279 return false 1280 } 1281 1282 return true 1283 } 1284 1285 // Import parses the contents of a libotr private key file. 1286 func (priv *PrivateKey) Import(in []byte) bool { 1287 mpiStart := []byte(" #") 1288 1289 mpis := make([]*big.Int, 5) 1290 1291 for i := 0; i < len(mpis); i++ { 1292 start := bytes.Index(in, mpiStart) 1293 if start == -1 { 1294 return false 1295 } 1296 in = in[start+len(mpiStart):] 1297 end := bytes.IndexFunc(in, notHex) 1298 if end == -1 { 1299 return false 1300 } 1301 hexBytes := in[:end] 1302 in = in[end:] 1303 1304 if len(hexBytes)&1 != 0 { 1305 return false 1306 } 1307 1308 mpiBytes := make([]byte, len(hexBytes)/2) 1309 if _, err := hex.Decode(mpiBytes, hexBytes); err != nil { 1310 return false 1311 } 1312 1313 mpis[i] = new(big.Int).SetBytes(mpiBytes) 1314 } 1315 1316 priv.PrivateKey.P = mpis[0] 1317 priv.PrivateKey.Q = mpis[1] 1318 priv.PrivateKey.G = mpis[2] 1319 priv.PrivateKey.Y = mpis[3] 1320 priv.PrivateKey.X = mpis[4] 1321 priv.PublicKey.PublicKey = priv.PrivateKey.PublicKey 1322 1323 a := new(big.Int).Exp(priv.PrivateKey.G, priv.PrivateKey.X, priv.PrivateKey.P) 1324 return a.Cmp(priv.PrivateKey.Y) == 0 1325 } 1326 1327 func getU8(in []byte) (uint8, []byte, bool) { 1328 if len(in) < 1 { 1329 return 0, in, false 1330 } 1331 return in[0], in[1:], true 1332 } 1333 1334 func getU16(in []byte) (uint16, []byte, bool) { 1335 if len(in) < 2 { 1336 return 0, in, false 1337 } 1338 r := uint16(in[0])<<8 | uint16(in[1]) 1339 return r, in[2:], true 1340 } 1341 1342 func getU32(in []byte) (uint32, []byte, bool) { 1343 if len(in) < 4 { 1344 return 0, in, false 1345 } 1346 r := uint32(in[0])<<24 | uint32(in[1])<<16 | uint32(in[2])<<8 | uint32(in[3]) 1347 return r, in[4:], true 1348 } 1349 1350 func getMPI(in []byte) (*big.Int, []byte, bool) { 1351 l, in, ok := getU32(in) 1352 if !ok || uint32(len(in)) < l { 1353 return nil, in, false 1354 } 1355 r := new(big.Int).SetBytes(in[:l]) 1356 return r, in[l:], true 1357 } 1358 1359 func getData(in []byte) ([]byte, []byte, bool) { 1360 l, in, ok := getU32(in) 1361 if !ok || uint32(len(in)) < l { 1362 return nil, in, false 1363 } 1364 return in[:l], in[l:], true 1365 } 1366 1367 func getNBytes(in []byte, n int) ([]byte, []byte, bool) { 1368 if len(in) < n { 1369 return nil, in, false 1370 } 1371 return in[:n], in[n:], true 1372 } 1373 1374 func appendU16(out []byte, v uint16) []byte { 1375 out = append(out, byte(v>>8), byte(v)) 1376 return out 1377 } 1378 1379 func appendU32(out []byte, v uint32) []byte { 1380 out = append(out, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 1381 return out 1382 } 1383 1384 func appendData(out, v []byte) []byte { 1385 out = appendU32(out, uint32(len(v))) 1386 out = append(out, v...) 1387 return out 1388 } 1389 1390 func appendMPI(out []byte, v *big.Int) []byte { 1391 vBytes := v.Bytes() 1392 out = appendU32(out, uint32(len(vBytes))) 1393 out = append(out, vBytes...) 1394 return out 1395 } 1396 1397 func appendMPIs(out []byte, mpis ...*big.Int) []byte { 1398 for _, mpi := range mpis { 1399 out = appendMPI(out, mpi) 1400 } 1401 return out 1402 } 1403 1404 func zero(b []byte) { 1405 for i := range b { 1406 b[i] = 0 1407 } 1408 }