aes解密错误fix

main
orestonce 2023-05-15 09:26:38 +08:00
parent dc26c9b80f
commit b866b25c2e
5 changed files with 166 additions and 41 deletions

View File

@ -181,9 +181,9 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
} }
} }
// 获取m3u8地址的内容体 // 获取m3u8地址的内容体
tsKey, err := this.getM3u8Key(req.M3u8Url, string(m3u8Body)) encInfo, err := this.getEncryptInfo(req.M3u8Url, string(m3u8Body))
if err != nil { if err != nil {
resp.ErrMsg = "getM3u8Key: " + err.Error() resp.ErrMsg = "getEncryptInfo: " + err.Error()
resp.IsCancel = this.GetIsCancel() resp.IsCancel = this.GetIsCancel()
return resp return resp
} }
@ -201,7 +201,7 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
// 下载ts // 下载ts
this.SetProgressBarTitle("[4/6]下载ts") this.SetProgressBarTitle("[4/6]下载ts")
this.speedSetBegin() this.speedSetBegin()
err = this.downloader(tsList, downloadDir, tsKey, req.ThreadCount) err = this.downloader(tsList, downloadDir, encInfo, req.ThreadCount)
this.speedClearBytes() this.speedClearBytes()
if err != nil { if err != nil {
resp.ErrMsg = "下载ts文件错误: " + err.Error() resp.ErrMsg = "下载ts文件错误: " + err.Error()
@ -343,34 +343,31 @@ func GetWd() string {
return wd return wd
} }
// 获取m3u8加密的密钥 // 获取m3u8加密的密钥, 可能存在iv
func (this *downloadEnv) getM3u8Key(m3u8Url string, html string) (key string, err error) { func (this *downloadEnv) getEncryptInfo(m3u8Url string, html string) (info *EncryptInfo, err error) {
key = "" keyPart := M3u8Parse(html).GetPart("#EXT-X-KEY")
for _, line := range splitLineWithTrimSpace(html) { uri := keyPart.KeyValue["URI"]
if strings.Contains(line, "#EXT-X-KEY") == false { if uri == "" {
continue return nil, nil
}
uriPos := strings.Index(line, "URI")
quotationMarkPos := strings.LastIndex(line, "\"")
if uriPos == -1 || quotationMarkPos == -1 {
continue
}
keyUrl := strings.Split(line[uriPos:quotationMarkPos], "\"")[1]
if !strings.Contains(line, "http") {
var errMsg string
keyUrl, errMsg = resolveRefUrl(m3u8Url, line)
if errMsg != "" {
return "", errors.New(errMsg)
}
}
var res []byte
res, err = this.doGetRequest(keyUrl)
if err != nil {
return "", err
}
return string(res), nil
} }
return "", nil keyUrl, errMsg := resolveRefUrl(m3u8Url, uri)
if errMsg != "" {
return nil, errors.New(errMsg)
}
var res []byte
res, err = this.doGetRequest(keyUrl)
if err != nil {
return nil, err
}
iv, err := hex.DecodeString(strings.TrimPrefix(keyPart.KeyValue["IV"], "0x"))
if err != nil {
return nil, err
}
return &EncryptInfo{
Method: keyPart.KeyValue["METHOD"],
Key: res,
Iv: iv,
}, nil
} }
func splitLineWithTrimSpace(s string) []string { func splitLineWithTrimSpace(s string) []string {
@ -405,7 +402,7 @@ func getTsList(m38uUrl string, body string) (tsList []TsInfo, errMsg string) {
// 下载ts文件 // 下载ts文件
// @modify: 2020-08-13 修复ts格式SyncByte合并不能播放问题 // @modify: 2020-08-13 修复ts格式SyncByte合并不能播放问题
func (this *downloadEnv) downloadTsFile(ts TsInfo, download_dir, key string) (err error) { func (this *downloadEnv) downloadTsFile(ts TsInfo, download_dir string, encInfo *EncryptInfo) (err error) {
currPath := fmt.Sprintf("%s/%s", download_dir, ts.Name) currPath := fmt.Sprintf("%s/%s", download_dir, ts.Name)
if isFileExists(currPath) { if isFileExists(currPath) {
return nil return nil
@ -418,9 +415,9 @@ func (this *downloadEnv) downloadTsFile(ts TsInfo, download_dir, key string) (er
var origData []byte var origData []byte
origData = data origData = data
// 解密出视频 ts 源文件 // 解密出视频 ts 源文件
if key != "" { if encInfo != nil {
//解密 ts 文件算法aes 128 cbc pack5 //解密 ts 文件算法aes 128 cbc pack5
origData, err = AesDecrypt(origData, []byte(key)) origData, err = AesDecrypt(origData, encInfo)
if err != nil { if err != nil {
return err return err
} }
@ -462,7 +459,7 @@ func (this *downloadEnv) SleepDur(d time.Duration) {
} }
} }
func (this *downloadEnv) downloader(tsList []TsInfo, downloadDir string, key string, threadCount int) (err error) { func (this *downloadEnv) downloader(tsList []TsInfo, downloadDir string, encInfo *EncryptInfo, threadCount int) (err error) {
if threadCount <= 0 || threadCount > 1000 { if threadCount <= 0 || threadCount > 1000 {
return errors.New("downloadEnv.threadCount invalid: " + strconv.Itoa(threadCount)) return errors.New("downloadEnv.threadCount invalid: " + strconv.Itoa(threadCount))
} }
@ -487,7 +484,7 @@ func (this *downloadEnv) downloader(tsList []TsInfo, downloadDir string, key str
this.SleepDur(time.Second * time.Duration(i)) this.SleepDur(time.Second * time.Duration(i))
atomic.AddInt32(&this.sleepTh, -1) atomic.AddInt32(&this.sleepTh, -1)
} }
lastErr = this.downloadTsFile(ts, downloadDir, key) lastErr = this.downloadTsFile(ts, downloadDir, encInfo)
if lastErr == nil { if lastErr == nil {
break break
} }
@ -549,13 +546,20 @@ func PKCS7UnPadding(origData []byte) []byte {
return origData[:(length - unpadding)] return origData[:(length - unpadding)]
} }
func AesDecrypt(crypted, key []byte) ([]byte, error) { func AesDecrypt(crypted []byte, encInfo *EncryptInfo) ([]byte, error) {
block, err := aes.NewCipher(key) block, err := aes.NewCipher(encInfo.Key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
blockSize := block.BlockSize() blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) iv := encInfo.Iv
if len(iv) == 0 {
if len(encInfo.Key) > blockSize {
return nil, errors.New(fmt.Sprint("AesDecrypt invalid size ", blockSize, " ", len(encInfo.Key)))
}
iv = encInfo.Key[:blockSize]
}
blockMode := cipher.NewCBCDecrypter(block, iv)
origData := make([]byte, len(crypted)) origData := make([]byte, len(crypted))
blockMode.CryptBlocks(origData, crypted) blockMode.CryptBlocks(origData, crypted)
origData = PKCS7UnPadding(origData) origData = PKCS7UnPadding(origData)

2
go.mod
View File

@ -8,7 +8,7 @@ require (
github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171 github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171
github.com/spf13/cobra v1.4.0 github.com/spf13/cobra v1.4.0
github.com/yapingcat/gomedia v0.0.0-20221023155149-c5f2f0f45ca5 github.com/yapingcat/gomedia v0.0.0-20221023155149-c5f2f0f45ca5
golang.org/x/text v0.3.7 golang.org/x/text v0.3.3
) )
require ( require (

4
go.sum
View File

@ -14,8 +14,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/yapingcat/gomedia v0.0.0-20221023155149-c5f2f0f45ca5 h1:dswmlgf8sSrjaQJCGDpmI14sIkHqyIZdP6Jwzl7gVDY= github.com/yapingcat/gomedia v0.0.0-20221023155149-c5f2f0f45ca5 h1:dswmlgf8sSrjaQJCGDpmI14sIkHqyIZdP6Jwzl7gVDY=
github.com/yapingcat/gomedia v0.0.0-20221023155149-c5f2f0f45ca5/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc= github.com/yapingcat/gomedia v0.0.0-20221023155149-c5f2f0f45ca5/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

71
m3u8.go Normal file
View File

@ -0,0 +1,71 @@
package m3u8d
import (
"strconv"
"strings"
)
type EncryptInfo struct {
Method string
Key []byte
Iv []byte
}
type M3u8Content struct {
PartList []M3u8Part `json:",omitempty"`
TsList []string `json:",omitempty"`
}
type M3u8Part struct {
Tag string `json:",omitempty"`
TextFull string `json:",omitempty"`
KeyValue map[string]string `json:",omitempty"`
}
func (info M3u8Content) GetPart(tag string) M3u8Part {
for _, one := range info.PartList {
if one.Tag == tag {
return one
}
}
return M3u8Part{}
}
func M3u8Parse(content string) (info M3u8Content) {
for _, line := range splitLineWithTrimSpace(content) {
if strings.HasPrefix(line, "#") == false {
continue
}
tmp := strings.SplitN(line, ":", 2)
if len(tmp) < 2 {
info.PartList = append(info.PartList, M3u8Part{
Tag: tmp[0],
})
continue
}
var p M3u8Part
p.Tag = tmp[0]
p.TextFull = strings.TrimSpace(tmp[1])
for _, kv := range strings.Split(tmp[1], ",") {
data := strings.SplitN(kv, "=", 2)
if len(data) < 2 {
continue
}
key := data[0]
value := strings.TrimSpace(data[1])
if strings.HasPrefix(value, "\"") {
var err error
value, err = strconv.Unquote(value)
if err != nil {
continue
}
}
if p.KeyValue == nil {
p.KeyValue = map[string]string{}
}
p.KeyValue[key] = value
}
info.PartList = append(info.PartList, p)
}
return info
}

50
m3u8_test.go Normal file
View File

@ -0,0 +1,50 @@
package m3u8d
import (
"encoding/hex"
"strconv"
"strings"
"testing"
)
func TestM3u8Parse(t *testing.T) {
info := M3u8Parse(`#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="/20230502/xthms/2000kb/hls/key.key"
`)
part := info.GetPart("#EXT-X-KEY")
if part.KeyValue["METHOD"] != "AES-128" {
panic("method")
}
if part.KeyValue["URI"] != "/20230502/xthms/2000kb/hls/key.key" {
panic("uri")
}
}
func TestGetFileNameFromUrl(t *testing.T) {
{
part := M3u8Parse(`#EXT-X-KEY:IV=0x10c27a9e3fa363dfe4c44b59b67304b3`).GetPart("#EXT-X-KEY")
iv, err := hex.DecodeString(strings.TrimPrefix(part.KeyValue["IV"], "0x"))
checkErr(err)
if len(iv) != 16 {
panic("iv " + strconv.Quote(string(iv)))
}
}
{
part := M3u8Parse(`#EXT-X-KEY:nothing`).GetPart("#EXT-X-KEY")
iv, err := hex.DecodeString(strings.TrimPrefix(part.KeyValue["IV"], "0x"))
checkErr(err)
if len(iv) != 0 {
panic("iv " + strconv.Quote(string(iv)))
}
}
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}