1 // https://wiki.vuze.com/w/Message_Stream_Encryption
19 "github.com/bradfitz/iter"
25 cryptoMethodPlaintext = 1
30 // Prime P according to the spec, and G, the generator.
32 // The rand.Int max arg for use in newPadLen()
34 // For use in initer's hashes
41 p.SetString("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563", 0)
43 newPadLenMax.SetInt64(maxPadLen + 1)
46 func hash(parts ...[]byte) []byte {
48 for _, p := range parts {
60 func newEncrypt(initer bool, s []byte, skey []byte) (c *rc4.Cipher) {
61 c, err := rc4.NewCipher(hash([]byte(func() string {
71 var burnSrc, burnDst [1024]byte
72 c.XORKeyStream(burnDst[:], burnSrc[:])
76 type cipherReader struct {
81 func (me *cipherReader) Read(b []byte) (n int, err error) {
82 be := make([]byte, len(b))
83 n, err = me.r.Read(be)
84 me.c.XORKeyStream(b[:n], be[:n])
88 func newCipherReader(c *rc4.Cipher, r io.Reader) io.Reader {
89 return &cipherReader{c, r}
92 type cipherWriter struct {
97 func (me *cipherWriter) Write(b []byte) (n int, err error) {
98 be := make([]byte, len(b))
99 me.c.XORKeyStream(be, b)
100 n, err = me.w.Write(be)
102 // The cipher will have advanced beyond the callers stream position.
103 // We can't use the cipher anymore.
109 func newCipherWriter(c *rc4.Cipher, w io.Writer) io.Writer {
110 return &cipherWriter{c, w}
113 func readY(r io.Reader) (y big.Int, err error) {
115 _, err = io.ReadFull(r, b[:])
123 func newX() big.Int {
125 X.SetBytes(func() []byte {
127 _, err := rand.Read(b[:])
136 func (h *handshake) postY(x *big.Int) error {
143 return h.postWrite(b)
146 func (h *handshake) establishS() (err error) {
150 _, err = io.ReadFull(h.conn, b[:])
160 func newPadLen() int64 {
161 i, err := rand.Int(rand.Reader, &newPadLenMax)
166 if ret < 0 || ret > maxPadLen {
172 type handshake struct {
173 conn io.ReadWriteCloser
189 func (h *handshake) finishWriting() (err error) {
192 h.writeCond.Broadcast()
205 func (h *handshake) writer() {
209 h.writerCond.Broadcast()
215 if len(h.writes) != 0 {
225 h.writes = h.writes[1:]
227 _, err := h.conn.Write(b)
237 func (h *handshake) postWrite(b []byte) error {
239 defer h.writeMu.Unlock()
240 if h.writeErr != nil {
243 h.writes = append(h.writes, b)
248 func xor(dst, src []byte) (ret []byte) {
253 ret = make([]byte, 0, max)
254 for i := range iter.N(max) {
255 ret = append(ret, dst[i]^src[i])
260 type cryptoNegotiation struct {
267 func (me *cryptoNegotiation) UnmarshalReader(r io.Reader) (err error) {
268 _, err = io.ReadFull(r, me.VC[:])
272 err = binary.Read(r, binary.BigEndian, &me.Method)
276 err = binary.Read(r, binary.BigEndian, &me.PadLen)
281 _, err = io.CopyN(ioutil.Discard, r, int64(me.PadLen))
285 func (me *cryptoNegotiation) MarshalWriter(w io.Writer) (err error) {
286 _, err = w.Write(me.VC[:])
290 err = binary.Write(w, binary.BigEndian, me.Method)
294 err = binary.Write(w, binary.BigEndian, me.PadLen)
298 _, err = w.Write(make([]byte, me.PadLen))
302 // Looking for b at the end of a.
303 func suffixMatchLen(a, b []byte) int {
307 // i is how much of b to try to match
308 for i := len(b); i > 0; i-- {
309 // j is how many chars we've compared
312 if b[i-1-j] != a[len(a)-1-j] {
322 func readUntil(r io.Reader, b []byte) error {
323 log.Println("read until", b)
324 b1 := make([]byte, len(b))
327 _, err := io.ReadFull(r, b1[i:])
331 i = suffixMatchLen(b1, b)
335 if copy(b1, b1[len(b1)-i:]) != i {
342 func (h *handshake) Do() (ret io.ReadWriteCloser, err error) {
347 pad := make([]byte, newPadLen())
348 io.ReadFull(rand.Reader, pad)
349 err = h.postWrite(pad)
354 h.postWrite(hash(req1, h.s.Bytes()))
355 h.postWrite(xor(hash(req2, h.skey), hash(req3, h.s.Bytes())))
356 buf := &bytes.Buffer{}
357 err = (&cryptoNegotiation{
358 Method: cryptoMethodRC4,
359 PadLen: uint16(newPadLen()),
360 }).MarshalWriter(buf)
364 e := newEncrypt(true, h.s.Bytes(), h.skey)
365 be := make([]byte, buf.Len())
366 e.XORKeyStream(be, buf.Bytes())
368 bC := newEncrypt(false, h.s.Bytes(), h.skey)
370 bC.XORKeyStream(eVC[:], make([]byte, 8))
372 // Read until the all zero VC.
373 err = readUntil(h.conn, eVC[:])
375 err = fmt.Errorf("error reading until VC: %s", err)
378 var cn cryptoNegotiation
379 r := &cipherReader{bC, h.conn}
380 err = cn.UnmarshalReader(io.MultiReader(bytes.NewReader(make([]byte, 8)), r))
381 log.Printf("initer got %v", cn)
383 err = fmt.Errorf("error reading crypto negotiation: %s", err)
387 err = readUntil(h.conn, hash(req1, h.s.Bytes()))
392 _, err = io.ReadFull(h.conn, b[:])
396 if !bytes.Equal(xor(hash(req2, h.skey), hash(req3, h.s.Bytes())), b[:]) {
397 err = errors.New("skey doesn't match")
400 var cn cryptoNegotiation
401 r := newCipherReader(newEncrypt(true, h.s.Bytes(), h.skey), h.conn)
402 err = cn.UnmarshalReader(r)
406 log.Printf("receiver got %v", cn)
407 if cn.Method&cryptoMethodRC4 == 0 {
408 err = errors.New("no supported crypto methods were provided")
411 buf := &bytes.Buffer{}
412 w := newCipherWriter(newEncrypt(false, h.s.Bytes(), h.skey), buf)
413 err = (&cryptoNegotiation{
414 Method: cryptoMethodRC4,
415 PadLen: uint16(newPadLen()),
420 log.Println("encrypted VC", buf.Bytes()[:8])
421 err = h.postWrite(buf.Bytes())
426 err = h.finishWriting()
434 func Handshake(rw io.ReadWriteCloser, initer bool, skey []byte) (ret io.ReadWriteCloser, err error) {
440 h.writeCond.L = &h.writeMu
441 h.writerCond.L = &h.writerMu