1 // https://wiki.vuze.com/w/Message_Stream_Encryption
20 "github.com/bradfitz/iter"
26 cryptoMethodPlaintext = 1
31 // Prime P according to the spec, and G, the generator.
33 // The rand.Int max arg for use in newPadLen()
35 // For use in initer's hashes
40 cryptoProvidesCount = expvar.NewMap("mseCryptoProvides")
44 p.SetString("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563", 0)
46 newPadLenMax.SetInt64(maxPadLen + 1)
49 func hash(parts ...[]byte) []byte {
51 for _, p := range parts {
63 func newEncrypt(initer bool, s []byte, skey []byte) (c *rc4.Cipher) {
64 c, err := rc4.NewCipher(hash([]byte(func() string {
74 var burnSrc, burnDst [1024]byte
75 c.XORKeyStream(burnDst[:], burnSrc[:])
79 type cipherReader struct {
84 func (me *cipherReader) Read(b []byte) (n int, err error) {
85 be := make([]byte, len(b))
86 n, err = me.r.Read(be)
87 me.c.XORKeyStream(b[:n], be[:n])
91 func newCipherReader(c *rc4.Cipher, r io.Reader) io.Reader {
92 return &cipherReader{c, r}
95 type cipherWriter struct {
100 func (me *cipherWriter) Write(b []byte) (n int, err error) {
101 be := make([]byte, len(b))
102 me.c.XORKeyStream(be, b)
103 n, err = me.w.Write(be)
105 // The cipher will have advanced beyond the callers stream position.
106 // We can't use the cipher anymore.
112 func readY(r io.Reader) (y big.Int, err error) {
114 _, err = io.ReadFull(r, b[:])
122 func newX() big.Int {
124 X.SetBytes(func() []byte {
126 _, err := rand.Read(b[:])
135 // Calculate, and send Y, our public key.
136 func (h *handshake) postY(x *big.Int) error {
141 b1 := make([]byte, 96)
142 if n := copy(b1[96-len(b):], b); n != len(b) {
147 return h.postWrite(b)
150 func (h *handshake) establishS() (err error) {
154 _, err = io.ReadFull(h.conn, b[:])
164 func newPadLen() int64 {
165 i, err := rand.Int(rand.Reader, &newPadLenMax)
170 if ret < 0 || ret > maxPadLen {
176 type handshake struct {
177 conn io.ReadWriteCloser
182 ia []byte // Initial payload. Only used by the initiator.
195 func (h *handshake) finishWriting() (err error) {
198 h.writeCond.Broadcast()
211 func (h *handshake) writer() {
215 h.writerCond.Broadcast()
221 if len(h.writes) != 0 {
231 h.writes = h.writes[1:]
233 _, err := h.conn.Write(b)
243 func (h *handshake) postWrite(b []byte) error {
245 defer h.writeMu.Unlock()
246 if h.writeErr != nil {
249 h.writes = append(h.writes, b)
254 func xor(dst, src []byte) (ret []byte) {
259 ret = make([]byte, 0, max)
260 for i := range iter.N(max) {
261 ret = append(ret, dst[i]^src[i])
266 func marshal(w io.Writer, data ...interface{}) (err error) {
267 for _, data := range data {
268 err = binary.Write(w, binary.BigEndian, data)
276 func unmarshal(r io.Reader, data ...interface{}) (err error) {
277 for _, data := range data {
278 err = binary.Read(r, binary.BigEndian, data)
286 type cryptoNegotiation struct {
293 func (me *cryptoNegotiation) UnmarshalReader(r io.Reader) (err error) {
294 err = binary.Read(r, binary.BigEndian, me.VC[:])
298 err = binary.Read(r, binary.BigEndian, &me.Method)
302 err = binary.Read(r, binary.BigEndian, &me.PadLen)
306 _, err = io.CopyN(ioutil.Discard, r, int64(me.PadLen))
310 func (me *cryptoNegotiation) MarshalWriter(w io.Writer) (err error) {
311 // _, err = w.Write(me.VC[:])
312 err = binary.Write(w, binary.BigEndian, me.VC[:])
316 err = binary.Write(w, binary.BigEndian, me.Method)
320 err = binary.Write(w, binary.BigEndian, me.PadLen)
324 _, err = w.Write(make([]byte, me.PadLen))
328 // Looking for b at the end of a.
329 func suffixMatchLen(a, b []byte) int {
333 // i is how much of b to try to match
334 for i := len(b); i > 0; i-- {
335 // j is how many chars we've compared
338 if b[i-1-j] != a[len(a)-1-j] {
348 func readUntil(r io.Reader, b []byte) error {
349 b1 := make([]byte, len(b))
352 _, err := io.ReadFull(r, b1[i:])
356 i = suffixMatchLen(b1, b)
360 if copy(b1, b1[len(b1)-i:]) != i {
367 type readWriter struct {
372 func (h *handshake) initerSteps() (ret io.ReadWriter, err error) {
373 h.postWrite(hash(req1, h.s.Bytes()))
374 h.postWrite(xor(hash(req2, h.skey), hash(req3, h.s.Bytes())))
375 buf := &bytes.Buffer{}
376 err = (&cryptoNegotiation{
377 Method: cryptoMethodRC4,
378 PadLen: uint16(newPadLen()),
379 }).MarshalWriter(buf)
383 err = marshal(buf, uint16(len(h.ia)), h.ia)
387 e := newEncrypt(true, h.s.Bytes(), h.skey)
388 be := make([]byte, buf.Len())
389 e.XORKeyStream(be, buf.Bytes())
391 bC := newEncrypt(false, h.s.Bytes(), h.skey)
393 bC.XORKeyStream(eVC[:], make([]byte, 8))
394 // Read until the all zero VC.
395 err = readUntil(h.conn, eVC[:])
397 err = fmt.Errorf("error reading until VC: %s", err)
400 var cn cryptoNegotiation
401 r := &cipherReader{bC, h.conn}
402 err = cn.UnmarshalReader(io.MultiReader(bytes.NewReader(make([]byte, 8)), r))
404 err = fmt.Errorf("error reading crypto negotiation: %s", err)
407 ret = readWriter{r, &cipherWriter{e, h.conn}}
411 func (h *handshake) receiverSteps() (ret io.ReadWriter, err error) {
412 err = readUntil(h.conn, hash(req1, h.s.Bytes()))
417 _, err = io.ReadFull(h.conn, b[:])
421 err = errors.New("skey doesn't match")
422 for _, skey := range h.skeys {
423 if bytes.Equal(xor(hash(req2, skey), hash(req3, h.s.Bytes())), b[:]) {
432 var cn cryptoNegotiation
433 r := newCipherReader(newEncrypt(true, h.s.Bytes(), h.skey), h.conn)
434 err = cn.UnmarshalReader(r)
438 cryptoProvidesCount.Add(strconv.FormatUint(uint64(cn.Method), 16), 1)
439 if cn.Method&cryptoMethodRC4 == 0 {
440 err = errors.New("no supported crypto methods were provided")
446 h.ia = make([]byte, lenIA)
449 buf := &bytes.Buffer{}
450 w := cipherWriter{newEncrypt(false, h.s.Bytes(), h.skey), buf}
451 err = (&cryptoNegotiation{
452 Method: cryptoMethodRC4,
453 PadLen: uint16(newPadLen()),
458 err = h.postWrite(buf.Bytes())
462 ret = readWriter{io.MultiReader(bytes.NewReader(h.ia), r), &cipherWriter{w.c, h.conn}}
466 func (h *handshake) Do() (ret io.ReadWriter, err error) {
469 err = fmt.Errorf("error while establishing secret: %s", err)
472 pad := make([]byte, newPadLen())
473 io.ReadFull(rand.Reader, pad)
474 err = h.postWrite(pad)
479 ret, err = h.initerSteps()
481 ret, err = h.receiverSteps()
486 err = h.finishWriting()
493 func InitiateHandshake(rw io.ReadWriteCloser, skey []byte, initialPayload []byte) (ret io.ReadWriter, err error) {
500 h.writeCond.L = &h.writeMu
501 h.writerCond.L = &h.writerMu
505 func ReceiveHandshake(rw io.ReadWriteCloser, skeys [][]byte) (ret io.ReadWriter, err error) {
511 h.writeCond.L = &h.writeMu
512 h.writerCond.L = &h.writerMu