mirror of
				https://github.com/aler9/rtsp-simple-server
				synced 2025-10-31 02:56:29 +08:00 
			
		
		
		
	 9e6abc6e9f
			
		
	
	9e6abc6e9f
	
	
	
		
			
			* rtmp: improve MsgCommandAMF0 * rtmp: fix MsgSetPeerBandwidth * rtmp: add message tests * rtmp: replace implementation with new one * rtmp: rename handshake functions * rtmp: avoid calling useless function * rtmp: use time.Duration for PTSDelta * rtmp: fix decoding chunks with relevant size * rtmp: rewrite implementation of rtmp connection * rtmp: fix tests * rtmp: improve error message * rtmp: replace h264 config implementation * link against github.com/notedit/rtmp * normalize MessageStreamID * rtmp: make acknowledge optional * rtmp: fix decoding of chunk2 + chunk3 * avoid using encoding/binary
		
			
				
	
	
		
			146 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package handshake
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"crypto/hmac"
 | |
| 	"crypto/rand"
 | |
| 	"crypto/sha256"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	hsClientFullKey = []byte{
 | |
| 		'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
 | |
| 		'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ',
 | |
| 		'0', '0', '1',
 | |
| 		0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1,
 | |
| 		0x02, 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB,
 | |
| 		0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE,
 | |
| 	}
 | |
| 	hsServerFullKey = []byte{
 | |
| 		'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
 | |
| 		'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
 | |
| 		'S', 'e', 'r', 'v', 'e', 'r', ' ',
 | |
| 		'0', '0', '1',
 | |
| 		0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1,
 | |
| 		0x02, 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB,
 | |
| 		0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE,
 | |
| 	}
 | |
| 	hsClientPartialKey = hsClientFullKey[:30]
 | |
| 	hsServerPartialKey = hsServerFullKey[:36]
 | |
| )
 | |
| 
 | |
| func hsCalcDigestPos(p []byte, base int) int {
 | |
| 	pos := 0
 | |
| 	for i := 0; i < 4; i++ {
 | |
| 		pos += int(p[base+i])
 | |
| 	}
 | |
| 	return (pos % 728) + base + 4
 | |
| }
 | |
| 
 | |
| func hsMakeDigest(key []byte, src []byte, gap int) []byte {
 | |
| 	h := hmac.New(sha256.New, key)
 | |
| 	if gap <= 0 {
 | |
| 		h.Write(src)
 | |
| 	} else {
 | |
| 		h.Write(src[:gap])
 | |
| 		h.Write(src[gap+32:])
 | |
| 	}
 | |
| 	return h.Sum(nil)
 | |
| }
 | |
| 
 | |
| func hsFindDigest(p []byte, key []byte, base int) int {
 | |
| 	gap := hsCalcDigestPos(p, base)
 | |
| 	digest := hsMakeDigest(key, p, gap)
 | |
| 	if !bytes.Equal(p[gap:gap+32], digest) {
 | |
| 		return -1
 | |
| 	}
 | |
| 	return gap
 | |
| }
 | |
| 
 | |
| func hsParse1(p []byte, peerkey []byte, key []byte) (bool, []byte) {
 | |
| 	var pos int
 | |
| 	if pos = hsFindDigest(p, peerkey, 772); pos == -1 {
 | |
| 		if pos = hsFindDigest(p, peerkey, 8); pos == -1 {
 | |
| 			return false, nil
 | |
| 		}
 | |
| 	}
 | |
| 	return true, hsMakeDigest(key, p[pos:pos+32], -1)
 | |
| }
 | |
| 
 | |
| // C1S1 is a C1 or S1 packet.
 | |
| type C1S1 struct {
 | |
| 	Time   uint32
 | |
| 	Random []byte
 | |
| 	Digest []byte
 | |
| }
 | |
| 
 | |
| // Read reads a C1S1.
 | |
| func (c *C1S1) Read(r io.Reader, isC1 bool, validateSignature bool) error {
 | |
| 	buf := make([]byte, 1536)
 | |
| 	_, err := io.ReadFull(r, buf)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	var peerKey []byte
 | |
| 	var key []byte
 | |
| 	if isC1 {
 | |
| 		peerKey = hsClientPartialKey
 | |
| 		key = hsServerFullKey
 | |
| 	} else {
 | |
| 		peerKey = hsServerPartialKey
 | |
| 		key = hsClientFullKey
 | |
| 	}
 | |
| 	ok, digest := hsParse1(buf, peerKey, key)
 | |
| 	if !ok {
 | |
| 		if validateSignature {
 | |
| 			return fmt.Errorf("unable to validate C1/S1 signature")
 | |
| 		}
 | |
| 	} else {
 | |
| 		c.Digest = digest
 | |
| 	}
 | |
| 
 | |
| 	c.Time = uint32(buf[0])<<24 | uint32(buf[1])<<16 | uint32(buf[2])<<8 | uint32(buf[3])
 | |
| 	c.Random = buf[8:]
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Write writes a C1S1.
 | |
| func (c *C1S1) Write(w io.Writer, isC1 bool) error {
 | |
| 	buf := make([]byte, 1536)
 | |
| 
 | |
| 	buf[0] = byte(c.Time >> 24)
 | |
| 	buf[1] = byte(c.Time >> 16)
 | |
| 	buf[2] = byte(c.Time >> 8)
 | |
| 	buf[3] = byte(c.Time)
 | |
| 	copy(buf[4:], []byte{0, 0, 0, 0})
 | |
| 
 | |
| 	if c.Random == nil {
 | |
| 		rand.Read(buf[8:])
 | |
| 	} else {
 | |
| 		copy(buf[8:], c.Random)
 | |
| 	}
 | |
| 
 | |
| 	// signature
 | |
| 	gap := hsCalcDigestPos(buf, 8)
 | |
| 	var peerKey []byte
 | |
| 	var key []byte
 | |
| 	if isC1 {
 | |
| 		peerKey = hsServerFullKey
 | |
| 		key = hsClientPartialKey
 | |
| 	} else {
 | |
| 		peerKey = hsClientFullKey
 | |
| 		key = hsServerPartialKey
 | |
| 	}
 | |
| 	digest := hsMakeDigest(key, buf, gap)
 | |
| 	copy(buf[gap:], digest)
 | |
| 	pos := hsFindDigest(buf, key, 8)
 | |
| 	c.Digest = hsMakeDigest(peerKey, buf[pos:pos+32], -1)
 | |
| 
 | |
| 	_, err := w.Write(buf)
 | |
| 	return err
 | |
| }
 |