mirror of
https://github.com/gwuhaolin/livego.git
synced 2021-06-01 09:10:22 +03:00
208 lines
4.5 KiB
Go
Executable File
208 lines
4.5 KiB
Go
Executable File
package core
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/hmac"
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"io"
|
|
|
|
"time"
|
|
|
|
"github.com/gwuhaolin/livego/utils/pio"
|
|
)
|
|
|
|
var (
|
|
timeout = 5 * time.Second
|
|
)
|
|
|
|
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 hsMakeDigest(key []byte, src []byte, gap int) (dst []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 hsCalcDigestPos(p []byte, base int) (pos int) {
|
|
for i := 0; i < 4; i++ {
|
|
pos += int(p[base+i])
|
|
}
|
|
pos = (pos % 728) + base + 4
|
|
return
|
|
}
|
|
|
|
func hsFindDigest(p []byte, key []byte, base int) int {
|
|
gap := hsCalcDigestPos(p, base)
|
|
digest := hsMakeDigest(key, p, gap)
|
|
if bytes.Compare(p[gap:gap+32], digest) != 0 {
|
|
return -1
|
|
}
|
|
return gap
|
|
}
|
|
|
|
func hsParse1(p []byte, peerkey []byte, key []byte) (ok bool, digest []byte) {
|
|
var pos int
|
|
if pos = hsFindDigest(p, peerkey, 772); pos == -1 {
|
|
if pos = hsFindDigest(p, peerkey, 8); pos == -1 {
|
|
return
|
|
}
|
|
}
|
|
ok = true
|
|
digest = hsMakeDigest(key, p[pos:pos+32], -1)
|
|
return
|
|
}
|
|
|
|
func hsCreate01(p []byte, time uint32, ver uint32, key []byte) {
|
|
p[0] = 3
|
|
p1 := p[1:]
|
|
rand.Read(p1[8:])
|
|
pio.PutU32BE(p1[0:4], time)
|
|
pio.PutU32BE(p1[4:8], ver)
|
|
gap := hsCalcDigestPos(p1, 8)
|
|
digest := hsMakeDigest(key, p1, gap)
|
|
copy(p1[gap:], digest)
|
|
}
|
|
|
|
func hsCreate2(p []byte, key []byte) {
|
|
rand.Read(p)
|
|
gap := len(p) - 32
|
|
digest := hsMakeDigest(key, p, gap)
|
|
copy(p[gap:], digest)
|
|
}
|
|
|
|
func (conn *Conn) HandshakeClient() (err error) {
|
|
var random [(1 + 1536*2) * 2]byte
|
|
|
|
C0C1C2 := random[:1536*2+1]
|
|
C0 := C0C1C2[:1]
|
|
C0C1 := C0C1C2[:1536+1]
|
|
C2 := C0C1C2[1536+1:]
|
|
|
|
S0S1S2 := random[1536*2+1:]
|
|
|
|
C0[0] = 3
|
|
// > C0C1
|
|
conn.Conn.SetDeadline(time.Now().Add(timeout))
|
|
if _, err = conn.rw.Write(C0C1); err != nil {
|
|
return
|
|
}
|
|
conn.Conn.SetDeadline(time.Now().Add(timeout))
|
|
if err = conn.rw.Flush(); err != nil {
|
|
return
|
|
}
|
|
|
|
// < S0S1S2
|
|
conn.Conn.SetDeadline(time.Now().Add(timeout))
|
|
if _, err = io.ReadFull(conn.rw, S0S1S2); err != nil {
|
|
return
|
|
}
|
|
|
|
S1 := S0S1S2[1 : 1536+1]
|
|
if ver := pio.U32BE(S1[4:8]); ver != 0 {
|
|
C2 = S1
|
|
} else {
|
|
C2 = S1
|
|
}
|
|
|
|
// > C2
|
|
conn.Conn.SetDeadline(time.Now().Add(timeout))
|
|
if _, err = conn.rw.Write(C2); err != nil {
|
|
return
|
|
}
|
|
conn.Conn.SetDeadline(time.Time{})
|
|
return
|
|
}
|
|
|
|
func (conn *Conn) HandshakeServer() (err error) {
|
|
var random [(1 + 1536*2) * 2]byte
|
|
|
|
C0C1C2 := random[:1536*2+1]
|
|
C0 := C0C1C2[:1]
|
|
C1 := C0C1C2[1 : 1536+1]
|
|
C0C1 := C0C1C2[:1536+1]
|
|
C2 := C0C1C2[1536+1:]
|
|
|
|
S0S1S2 := random[1536*2+1:]
|
|
S0 := S0S1S2[:1]
|
|
S1 := S0S1S2[1 : 1536+1]
|
|
S0S1 := S0S1S2[:1536+1]
|
|
S2 := S0S1S2[1536+1:]
|
|
|
|
// < C0C1
|
|
conn.Conn.SetDeadline(time.Now().Add(timeout))
|
|
if _, err = io.ReadFull(conn.rw, C0C1); err != nil {
|
|
return
|
|
}
|
|
conn.Conn.SetDeadline(time.Now().Add(timeout))
|
|
if C0[0] != 3 {
|
|
err = fmt.Errorf("rtmp: handshake version=%d invalid", C0[0])
|
|
return
|
|
}
|
|
|
|
S0[0] = 3
|
|
|
|
clitime := pio.U32BE(C1[0:4])
|
|
srvtime := clitime
|
|
srvver := uint32(0x0d0e0a0d)
|
|
cliver := pio.U32BE(C1[4:8])
|
|
|
|
if cliver != 0 {
|
|
var ok bool
|
|
var digest []byte
|
|
if ok, digest = hsParse1(C1, hsClientPartialKey, hsServerFullKey); !ok {
|
|
err = fmt.Errorf("rtmp: handshake server: C1 invalid")
|
|
return
|
|
}
|
|
hsCreate01(S0S1, srvtime, srvver, hsServerPartialKey)
|
|
hsCreate2(S2, digest)
|
|
} else {
|
|
copy(S1, C2)
|
|
copy(S2, C1)
|
|
}
|
|
|
|
// > S0S1S2
|
|
conn.Conn.SetDeadline(time.Now().Add(timeout))
|
|
if _, err = conn.rw.Write(S0S1S2); err != nil {
|
|
return
|
|
}
|
|
conn.Conn.SetDeadline(time.Now().Add(timeout))
|
|
if err = conn.rw.Flush(); err != nil {
|
|
return
|
|
}
|
|
|
|
// < C2
|
|
conn.Conn.SetDeadline(time.Now().Add(timeout))
|
|
if _, err = io.ReadFull(conn.rw, C2); err != nil {
|
|
return
|
|
}
|
|
conn.Conn.SetDeadline(time.Time{})
|
|
return
|
|
}
|