Fix support HKSV for HomeKit cameras #684

This commit is contained in:
Alex X
2025-03-12 22:28:30 +03:00
parent 6a4c73db03
commit 60250a32c2
7 changed files with 364 additions and 42 deletions
+17
View File
@@ -0,0 +1,17 @@
package camera
const TypeSetupDataStreamTransport = "131"
type SetupDataStreamRequest struct {
SessionCommandType byte `tlv8:"1"`
TransportType byte `tlv8:"2"`
ControllerKeySalt string `tlv8:"3"`
}
type SetupDataStreamResponse struct {
Status byte `tlv8:"1"`
TransportTypeSessionParameters struct {
TCPListeningPort uint16 `tlv8:"1"`
} `tlv8:"2"`
AccessoryKeySalt string `tlv8:"3"`
}
+123
View File
@@ -0,0 +1,123 @@
// Package hds - HomeKit Data Stream
package hds
import (
"bufio"
"encoding/binary"
"io"
"net"
"time"
"github.com/AlexxIT/go2rtc/pkg/hap/chacha20poly1305"
"github.com/AlexxIT/go2rtc/pkg/hap/hkdf"
"github.com/AlexxIT/go2rtc/pkg/hap/secure"
)
func Client(conn net.Conn, key []byte, salt string, controller bool) (*Conn, error) {
writeKey, err := hkdf.Sha512(key, salt, "HDS-Write-Encryption-Key")
if err != nil {
return nil, err
}
readKey, err := hkdf.Sha512(key, salt, "HDS-Read-Encryption-Key")
if err != nil {
return nil, err
}
c := &Conn{
conn: conn,
rd: bufio.NewReaderSize(conn, 32*1024),
wr: bufio.NewWriterSize(conn, 32*1024),
}
if controller {
c.decryptKey, c.encryptKey = readKey, writeKey
} else {
c.decryptKey, c.encryptKey = writeKey, readKey
}
return c, nil
}
type Conn struct {
conn net.Conn
rd *bufio.Reader
wr *bufio.Writer
decryptKey []byte
encryptKey []byte
decryptCnt uint64
encryptCnt uint64
}
func (c *Conn) Read(p []byte) (n int, err error) {
verify := make([]byte, 4)
if _, err = io.ReadFull(c.rd, verify); err != nil {
return
}
n = int(binary.BigEndian.Uint32(verify) & 0xFFFFFF)
ciphertext := make([]byte, n+secure.Overhead)
if _, err = io.ReadFull(c.rd, ciphertext); err != nil {
return
}
nonce := make([]byte, secure.NonceSize)
binary.LittleEndian.PutUint64(nonce, c.decryptCnt)
c.decryptCnt++
_, err = chacha20poly1305.DecryptAndVerify(c.decryptKey, p[:0], nonce, ciphertext, verify)
return
}
func (c *Conn) Write(b []byte) (n int, err error) {
n = len(b)
verify := make([]byte, 4)
binary.BigEndian.PutUint32(verify, 0x01000000|uint32(n))
if _, err = c.wr.Write(verify); err != nil {
return
}
nonce := make([]byte, secure.NonceSize)
binary.LittleEndian.PutUint64(nonce, c.encryptCnt)
c.encryptCnt++
buf := make([]byte, n+secure.Overhead)
if _, err = chacha20poly1305.EncryptAndSeal(c.encryptKey, buf[:0], nonce, b, verify); err != nil {
return
}
if _, err = c.wr.Write(buf); err != nil {
return
}
err = c.wr.Flush()
return
}
func (c *Conn) Close() error {
return c.conn.Close()
}
func (c *Conn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *Conn) RemoteAddr() net.Addr {
return c.conn.RemoteAddr()
}
func (c *Conn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *Conn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *Conn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
+35
View File
@@ -0,0 +1,35 @@
package hds
import (
"bufio"
"bytes"
"testing"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/stretchr/testify/require"
)
func TestEncryption(t *testing.T) {
key := []byte(core.RandString(16, 0))
salt := core.RandString(32, 0)
c, err := Client(nil, key, salt, true)
require.NoError(t, err)
buf := bytes.NewBuffer(nil)
c.wr = bufio.NewWriter(buf)
n, err := c.Write([]byte("test"))
require.NoError(t, err)
require.Equal(t, 4, n)
c, err = Client(nil, key, salt, false)
c.rd = bufio.NewReader(buf)
require.NoError(t, err)
b := make([]byte, 32)
n, err = c.Read(b)
require.NoError(t, err)
require.Equal(t, "test", string(b[:n]))
}
+5 -4
View File
@@ -64,10 +64,11 @@ type JSONCharacters struct {
}
type JSONCharacter struct {
AID uint8 `json:"aid"`
IID uint64 `json:"iid"`
Value any `json:"value,omitempty"`
Event any `json:"ev,omitempty"`
AID uint8 `json:"aid"`
IID uint64 `json:"iid"`
Status any `json:"status,omitempty"`
Value any `json:"value,omitempty"`
Event any `json:"ev,omitempty"`
}
func SanitizePin(pin string) (string, error) {
+3 -2
View File
@@ -6,7 +6,6 @@ import (
"errors"
"io"
"net"
"sync"
"time"
"github.com/AlexxIT/go2rtc/pkg/hap/chacha20poly1305"
@@ -24,7 +23,7 @@ type Conn struct {
encryptCnt uint64
decryptCnt uint64
mx sync.Mutex
SharedKey []byte
}
func Client(conn net.Conn, sharedKey []byte, isClient bool) (net.Conn, error) {
@@ -42,6 +41,8 @@ func Client(conn net.Conn, sharedKey []byte, isClient bool) (net.Conn, error) {
conn: conn,
rd: bufio.NewReaderSize(conn, 32*1024),
wr: bufio.NewWriterSize(conn, 32*1024),
SharedKey: sharedKey,
}
if isClient {