1 // https://wiki.vuze.com/w/Message_Stream_Encryption
21 "github.com/bradfitz/iter"
27 CryptoMethodPlaintext = 1
29 AllSupportedCrypto = CryptoMethodPlaintext | CryptoMethodRC4
33 // Prime P according to the spec, and G, the generator.
35 // The rand.Int max arg for use in newPadLen()
37 // For use in initer's hashes
41 // Verification constant "VC" which is all zeroes in the bittorrent
46 // Tracks counts of received crypto_provides
47 cryptoProvidesCount = expvar.NewMap("mseCryptoProvides")
51 p.SetString("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563", 0)
53 newPadLenMax.SetInt64(maxPadLen + 1)
56 func hash(parts ...[]byte) []byte {
58 for _, p := range parts {
70 func newEncrypt(initer bool, s []byte, skey []byte) (c *rc4.Cipher) {
71 c, err := rc4.NewCipher(hash([]byte(func() string {
81 var burnSrc, burnDst [1024]byte
82 c.XORKeyStream(burnDst[:], burnSrc[:])
86 type cipherReader struct {
93 func (cr *cipherReader) Read(b []byte) (n int, err error) {
96 if len(cr.be) >= len(b) {
102 be = make([]byte, len(b))
104 n, err = cr.r.Read(be[:len(b)])
105 cr.c.XORKeyStream(b[:n], be[:n])
107 if len(be) > len(cr.be) {
114 func newCipherReader(c *rc4.Cipher, r io.Reader) io.Reader {
115 return &cipherReader{c: c, r: r}
118 type cipherWriter struct {
124 func (cr *cipherWriter) Write(b []byte) (n int, err error) {
125 be := func() []byte {
126 if len(cr.b) < len(b) {
127 return make([]byte, len(b))
134 cr.c.XORKeyStream(be[:], b)
135 n, err = cr.w.Write(be[:len(b)])
137 // The cipher will have advanced beyond the callers stream position.
138 // We can't use the cipher anymore.
141 if len(be) > len(cr.b) {
147 func newX() big.Int {
149 X.SetBytes(func() []byte {
151 _, err := rand.Read(b[:])
160 func paddedLeft(b []byte, _len int) []byte {
164 ret := make([]byte, _len)
165 if n := copy(ret[_len-len(b):], b); n != len(b) {
171 // Calculate, and send Y, our public key.
172 func (h *handshake) postY(x *big.Int) error {
175 return h.postWrite(paddedLeft(y.Bytes(), 96))
178 func (h *handshake) establishS() (err error) {
182 _, err = io.ReadFull(h.conn, b[:])
190 copy(h.s[96-len(sBytes):96], sBytes)
194 func newPadLen() int64 {
195 i, err := rand.Int(rand.Reader, &newPadLenMax)
200 if ret < 0 || ret > maxPadLen {
206 // Manages state for both initiating and receiving handshakes.
207 type handshake struct {
210 initer bool // Whether we're initiating or receiving.
211 skeys SecretKeyIter // Skeys we'll accept if receiving.
212 skey []byte // Skey we're initiating with.
213 ia []byte // Initial payload. Only used by the initiator.
214 // Return the bit for the crypto method the receiver wants to use.
215 chooseMethod func(supported uint32) uint32
216 // Sent to the receiver.
217 cryptoProvides uint32
230 func (h *handshake) finishWriting() {
233 h.writeCond.Broadcast()
243 func (h *handshake) writer() {
247 h.writerCond.Broadcast()
253 if len(h.writes) != 0 {
263 h.writes = h.writes[1:]
265 _, err := h.conn.Write(b)
275 func (h *handshake) postWrite(b []byte) error {
277 defer h.writeMu.Unlock()
278 if h.writeErr != nil {
281 h.writes = append(h.writes, b)
286 func xor(dst, src []byte) (ret []byte) {
291 ret = make([]byte, 0, max)
292 for i := range iter.N(max) {
293 ret = append(ret, dst[i]^src[i])
298 func marshal(w io.Writer, data ...interface{}) (err error) {
299 for _, data := range data {
300 err = binary.Write(w, binary.BigEndian, data)
308 func unmarshal(r io.Reader, data ...interface{}) (err error) {
309 for _, data := range data {
310 err = binary.Read(r, binary.BigEndian, data)
318 // Looking for b at the end of a.
319 func suffixMatchLen(a, b []byte) int {
323 // i is how much of b to try to match
324 for i := len(b); i > 0; i-- {
325 // j is how many chars we've compared
328 if b[i-1-j] != a[len(a)-1-j] {
338 // Reads from r until b has been seen. Keeps the minimum amount of data in
340 func readUntil(r io.Reader, b []byte) error {
341 b1 := make([]byte, len(b))
344 _, err := io.ReadFull(r, b1[i:])
348 i = suffixMatchLen(b1, b)
352 if copy(b1, b1[len(b1)-i:]) != i {
359 type readWriter struct {
364 func (h *handshake) newEncrypt(initer bool) *rc4.Cipher {
365 return newEncrypt(initer, h.s[:], h.skey)
368 func (h *handshake) initerSteps() (ret io.ReadWriter, err error) {
369 h.postWrite(hash(req1, h.s[:]))
370 h.postWrite(xor(hash(req2, h.skey), hash(req3, h.s[:])))
371 buf := &bytes.Buffer{}
372 padLen := uint16(newPadLen())
373 if len(h.ia) > math.MaxUint16 {
374 err = errors.New("initial payload too large")
377 err = marshal(buf, vc[:], h.cryptoProvides, padLen, zeroPad[:padLen], uint16(len(h.ia)), h.ia)
381 e := h.newEncrypt(true)
382 be := make([]byte, buf.Len())
383 e.XORKeyStream(be, buf.Bytes())
385 bC := h.newEncrypt(false)
387 bC.XORKeyStream(eVC[:], vc[:])
388 // Read until the all zero VC. At this point we've only read the 96 byte
389 // public key, Y. There is potentially 512 byte padding, between us and
390 // the 8 byte verification constant.
391 err = readUntil(io.LimitReader(h.conn, 520), eVC[:])
394 err = errors.New("failed to synchronize on VC")
396 err = fmt.Errorf("error reading until VC: %s", err)
400 r := newCipherReader(bC, h.conn)
402 err = unmarshal(r, &method, &padLen)
406 _, err = io.CopyN(ioutil.Discard, r, int64(padLen))
410 switch method & h.cryptoProvides {
411 case CryptoMethodRC4:
412 ret = readWriter{r, &cipherWriter{e, h.conn, nil}}
413 case CryptoMethodPlaintext:
416 err = fmt.Errorf("receiver chose unsupported method: %x", method)
421 var ErrNoSecretKeyMatch = errors.New("no skey matched")
423 func (h *handshake) receiverSteps() (ret io.ReadWriter, err error) {
424 // There is up to 512 bytes of padding, then the 20 byte hash.
425 err = readUntil(io.LimitReader(h.conn, 532), hash(req1, h.s[:]))
428 err = errors.New("failed to synchronize on S hash")
433 _, err = io.ReadFull(h.conn, b[:])
437 err = ErrNoSecretKeyMatch
438 h.skeys(func(skey []byte) bool {
439 if bytes.Equal(xor(hash(req2, skey), hash(req3, h.s[:])), b[:]) {
449 r := newCipherReader(newEncrypt(true, h.s[:], h.skey), h.conn)
456 err = unmarshal(r, vc[:], &provides, &padLen)
460 cryptoProvidesCount.Add(strconv.FormatUint(uint64(provides), 16), 1)
461 chosen := h.chooseMethod(provides)
462 _, err = io.CopyN(ioutil.Discard, r, int64(padLen))
469 h.ia = make([]byte, lenIA)
472 buf := &bytes.Buffer{}
473 w := cipherWriter{h.newEncrypt(false), buf, nil}
474 padLen = uint16(newPadLen())
475 err = marshal(&w, &vc, uint32(chosen), padLen, zeroPad[:padLen])
479 err = h.postWrite(buf.Bytes())
484 case CryptoMethodRC4:
486 io.MultiReader(bytes.NewReader(h.ia), r),
487 &cipherWriter{w.c, h.conn, nil},
489 case CryptoMethodPlaintext:
491 io.MultiReader(bytes.NewReader(h.ia), h.conn),
495 err = errors.New("chosen crypto method is not supported")
500 func (h *handshake) Do() (ret io.ReadWriter, err error) {
501 h.writeCond.L = &h.writeMu
502 h.writerCond.L = &h.writerMu
512 err = fmt.Errorf("error while establishing secret: %s", err)
515 pad := make([]byte, newPadLen())
516 io.ReadFull(rand.Reader, pad)
517 err = h.postWrite(pad)
522 ret, err = h.initerSteps()
524 ret, err = h.receiverSteps()
529 func InitiateHandshake(rw io.ReadWriter, skey []byte, initialPayload []byte, cryptoProvides uint32) (ret io.ReadWriter, err error) {
535 cryptoProvides: cryptoProvides,
540 func ReceiveHandshake(rw io.ReadWriter, skeys SecretKeyIter, selectCrypto func(uint32) uint32) (ret io.ReadWriter, err error) {
545 chooseMethod: selectCrypto,
550 // A function that given a function, calls it with secret keys until it
551 // returns false or exhausted.
552 type SecretKeyIter func(callback func(skey []byte) (more bool))
554 func DefaultCryptoSelector(provided uint32) uint32 {
555 if provided&CryptoMethodPlaintext != 0 {
556 return CryptoMethodPlaintext
558 return CryptoMethodRC4
561 type CryptoSelector func(uint32) uint32