Files
go2rtc/pkg/roborock/iot/crypto.go
T
Sergey Krashevich 2b7682cdb3 refactor(dvrip): simplify broadcast loop structure
- replace traditional for loop with range-based for loop for clarity

refactor(ffmpeg): simplify cut function loop
- utilize range-based for loop instead of traditional for loop

refactor(ring): update API response mapping type
- change map type from `interface{}` to `any` for better type safety

refactor(stream): handle nil source in NewStream
- add nil check for source elements before processing

refactor(webrtc): unify payload handling in GetToken
- change map type from `interface{}` to `any` for consistency

refactor(ascii): optimize nested loops in Write function
- replace traditional for loops with range-based for loops for readability

refactor(bits): enhance readability in Reader methods
- replace traditional for loops with range-based for loops in Read functions

refactor(h264): modernize loop structures in DecodeConfig
- switch to range-based for loops for cleaner code

refactor(h265): streamline profile_tier_level loops
- utilize range-based for loops instead of traditional for loops

chore(core): remove commented-out test function for clarity

refactor(core): simplify RandString function loop
- change traditional for loop to range-based for loop

refactor(flvt): optimize timestamp handling in TestTimeToRTP
- switch to range-based for loop for iterating frames

refactor(nest): improve error handling in ExchangeSDP
- format error message with printf-style formatting for clarity

refactor(tapo): enhance securityEncode function
- change traditional for loop to range-based for loop for readability

fix(tcp): correct masking in websocket Write method
- replace traditional for loop with range-based for loop

refactor(tutk): modernize encoding loops in crypto functions
- utilize range-based for loops for better readability

refactor(tuya): unify data types in MQTT message struct
- change map type from `interface{}` to `any` for consistency

refactor(webrtc): standardize codec registration
- change map type from `interface{}` to `any` for type safety

refactor(yaml): simplify Unmarshal function signature
- update parameter type from `interface{}` to `any` for better clarity
2026-03-10 23:26:45 +03:00

116 lines
2.6 KiB
Go

package iot
import (
"crypto/aes"
"crypto/md5"
"encoding/binary"
"errors"
"hash/crc32"
)
// key - convert timestamp to key
func (c *Codec) key(timestamp uint32) []byte {
const salt = "TXdfu$jyZ#TZHsg4"
key := md5.Sum([]byte(encodeTimestamp(timestamp) + c.devKey + salt))
return key[:]
}
func (c *Codec) Decrypt(cipherText []byte) ([]byte, error) {
if len(cipherText) < 32 || string(cipherText[:3]) != "1.0" {
return nil, errors.New("wrong message prefix")
}
i := len(cipherText) - 4
if binary.BigEndian.Uint32(cipherText[i:]) != crc32.ChecksumIEEE(cipherText[:i]) {
return nil, errors.New("wrong message checksum")
}
if proto := binary.BigEndian.Uint16(cipherText[15:]); proto != 102 {
return nil, nil
}
timestamp := binary.BigEndian.Uint32(cipherText[11:])
return decryptECB(cipherText[19:i], c.key(timestamp)), nil
}
func (c *Codec) Encrypt(plainText []byte, seq, random, timestamp uint32) []byte {
const proto = 101
cipherText := encryptECB(plainText, c.key(timestamp))
size := uint16(len(cipherText))
msg := make([]byte, 23+size)
copy(msg, "1.0")
binary.BigEndian.PutUint32(msg[3:], seq)
binary.BigEndian.PutUint32(msg[7:], random)
binary.BigEndian.PutUint32(msg[11:], timestamp)
binary.BigEndian.PutUint16(msg[15:], proto)
binary.BigEndian.PutUint16(msg[17:], size)
copy(msg[19:], cipherText)
crc := crc32.ChecksumIEEE(msg[:19+size])
binary.BigEndian.PutUint32(msg[19+size:], crc)
return msg
}
func encodeTimestamp(i uint32) string {
const hextable = "0123456789abcdef"
b := []byte{
hextable[i>>8&0xF], hextable[i>>4&0xF],
hextable[i>>16&0xF], hextable[i&0xF],
hextable[i>>24&0xF], hextable[i>>20&0xF],
hextable[i>>28&0xF], hextable[i>>12&0xF],
}
return string(b)
}
func pad(plainText []byte, blockSize int) []byte {
b0 := byte(blockSize - len(plainText)%blockSize)
for range b0 {
plainText = append(plainText, b0)
}
return plainText
}
func unpad(paddedText []byte) []byte {
padSize := int(paddedText[len(paddedText)-1])
return paddedText[:len(paddedText)-padSize]
}
func encryptECB(plainText, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
blockSize := block.BlockSize()
plainText = pad(plainText, blockSize)
cipherText := plainText
for len(plainText) > 0 {
block.Encrypt(plainText, plainText)
plainText = plainText[blockSize:]
}
return cipherText
}
func decryptECB(cipherText, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
blockSize := block.BlockSize()
paddedText := cipherText
for len(cipherText) > 0 {
block.Decrypt(cipherText, cipherText)
cipherText = cipherText[blockSize:]
}
return unpad(paddedText)
}