998c85d6f5
- support qr code auth - support resolution change - support h265 - refactor code
135 lines
2.7 KiB
Go
135 lines
2.7 KiB
Go
package tuya
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"math/rand"
|
|
)
|
|
|
|
// https://github.com/tuya/tuya-device-sharing-sdk/blob/main/tuya_sharing/customerapi.py
|
|
func AesGCMEncrypt(rawData string, secret string) (string, error) {
|
|
nonce := []byte(RandomNonce(12))
|
|
|
|
block, err := aes.NewCipher([]byte(secret))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
aesgcm, err := cipher.NewGCM(block)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
ciphertext := aesgcm.Seal(nil, nonce, []byte(rawData), nil)
|
|
nonceB64 := base64.StdEncoding.EncodeToString(nonce)
|
|
ciphertextB64 := base64.StdEncoding.EncodeToString(ciphertext)
|
|
|
|
return nonceB64 + ciphertextB64, nil
|
|
}
|
|
|
|
func AesGCMDecrypt(cipherData string, secret string) (string, error) {
|
|
if len(cipherData) <= 16 {
|
|
return "", fmt.Errorf("invalid ciphertext length")
|
|
}
|
|
|
|
nonceB64 := cipherData[:16]
|
|
ciphertextB64 := cipherData[16:]
|
|
|
|
nonce, err := base64.StdEncoding.DecodeString(nonceB64)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
ciphertext, err := base64.StdEncoding.DecodeString(ciphertextB64)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
block, err := aes.NewCipher([]byte(secret))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
aesgcm, err := cipher.NewGCM(block)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return string(plaintext), nil
|
|
}
|
|
|
|
func SecretGenerating(rid, sid, hashKey string) string {
|
|
message := hashKey
|
|
mod := 16
|
|
|
|
if sid != "" {
|
|
sidLength := len(sid)
|
|
length := sidLength
|
|
if length > mod {
|
|
length = mod
|
|
}
|
|
|
|
ecode := ""
|
|
for i := 0; i < length; i++ {
|
|
idx := int(sid[i]) % mod
|
|
ecode += string(sid[idx])
|
|
}
|
|
message += "_"
|
|
message += ecode
|
|
}
|
|
|
|
h := hmac.New(sha256.New, []byte(rid))
|
|
h.Write([]byte(message))
|
|
byteTemp := h.Sum(nil)
|
|
secret := hex.EncodeToString(byteTemp)
|
|
|
|
return secret[:16]
|
|
}
|
|
|
|
func RestfulSign(hashKey, queryEncdata, bodyEncdata string, data map[string]string) string {
|
|
headers := []string{"X-appKey", "X-requestId", "X-sid", "X-time", "X-token"}
|
|
headerSignStr := ""
|
|
|
|
for _, item := range headers {
|
|
val, exists := data[item]
|
|
if exists && val != "" {
|
|
headerSignStr += item + "=" + val + "||"
|
|
}
|
|
}
|
|
|
|
signStr := ""
|
|
if len(headerSignStr) > 2 {
|
|
signStr = headerSignStr[:len(headerSignStr)-2]
|
|
}
|
|
|
|
if queryEncdata != "" {
|
|
signStr += queryEncdata
|
|
}
|
|
if bodyEncdata != "" {
|
|
signStr += bodyEncdata
|
|
}
|
|
|
|
h := hmac.New(sha256.New, []byte(hashKey))
|
|
h.Write([]byte(signStr))
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
}
|
|
|
|
func RandomNonce(length int) string {
|
|
const charset = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678"
|
|
result := make([]byte, length)
|
|
for i := range result {
|
|
result[i] = charset[rand.Intn(len(charset))]
|
|
}
|
|
return string(result)
|
|
}
|