aes解密错误fix
parent
dc26c9b80f
commit
b866b25c2e
80
download.go
80
download.go
|
|
@ -181,9 +181,9 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
|
|||
}
|
||||
}
|
||||
// 获取m3u8地址的内容体
|
||||
tsKey, err := this.getM3u8Key(req.M3u8Url, string(m3u8Body))
|
||||
encInfo, err := this.getEncryptInfo(req.M3u8Url, string(m3u8Body))
|
||||
if err != nil {
|
||||
resp.ErrMsg = "getM3u8Key: " + err.Error()
|
||||
resp.ErrMsg = "getEncryptInfo: " + err.Error()
|
||||
resp.IsCancel = this.GetIsCancel()
|
||||
return resp
|
||||
}
|
||||
|
|
@ -201,7 +201,7 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
|
|||
// 下载ts
|
||||
this.SetProgressBarTitle("[4/6]下载ts")
|
||||
this.speedSetBegin()
|
||||
err = this.downloader(tsList, downloadDir, tsKey, req.ThreadCount)
|
||||
err = this.downloader(tsList, downloadDir, encInfo, req.ThreadCount)
|
||||
this.speedClearBytes()
|
||||
if err != nil {
|
||||
resp.ErrMsg = "下载ts文件错误: " + err.Error()
|
||||
|
|
@ -343,34 +343,31 @@ func GetWd() string {
|
|||
return wd
|
||||
}
|
||||
|
||||
// 获取m3u8加密的密钥
|
||||
func (this *downloadEnv) getM3u8Key(m3u8Url string, html string) (key string, err error) {
|
||||
key = ""
|
||||
for _, line := range splitLineWithTrimSpace(html) {
|
||||
if strings.Contains(line, "#EXT-X-KEY") == false {
|
||||
continue
|
||||
}
|
||||
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
|
||||
// 获取m3u8加密的密钥, 可能存在iv
|
||||
func (this *downloadEnv) getEncryptInfo(m3u8Url string, html string) (info *EncryptInfo, err error) {
|
||||
keyPart := M3u8Parse(html).GetPart("#EXT-X-KEY")
|
||||
uri := keyPart.KeyValue["URI"]
|
||||
if uri == "" {
|
||||
return nil, 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 {
|
||||
|
|
@ -405,7 +402,7 @@ func getTsList(m38uUrl string, body string) (tsList []TsInfo, errMsg string) {
|
|||
|
||||
// 下载ts文件
|
||||
// @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)
|
||||
if isFileExists(currPath) {
|
||||
return nil
|
||||
|
|
@ -418,9 +415,9 @@ func (this *downloadEnv) downloadTsFile(ts TsInfo, download_dir, key string) (er
|
|||
var origData []byte
|
||||
origData = data
|
||||
// 解密出视频 ts 源文件
|
||||
if key != "" {
|
||||
if encInfo != nil {
|
||||
//解密 ts 文件,算法:aes 128 cbc pack5
|
||||
origData, err = AesDecrypt(origData, []byte(key))
|
||||
origData, err = AesDecrypt(origData, encInfo)
|
||||
if err != nil {
|
||||
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 {
|
||||
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))
|
||||
atomic.AddInt32(&this.sleepTh, -1)
|
||||
}
|
||||
lastErr = this.downloadTsFile(ts, downloadDir, key)
|
||||
lastErr = this.downloadTsFile(ts, downloadDir, encInfo)
|
||||
if lastErr == nil {
|
||||
break
|
||||
}
|
||||
|
|
@ -549,13 +546,20 @@ func PKCS7UnPadding(origData []byte) []byte {
|
|||
return origData[:(length - unpadding)]
|
||||
}
|
||||
|
||||
func AesDecrypt(crypted, key []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
func AesDecrypt(crypted []byte, encInfo *EncryptInfo) ([]byte, error) {
|
||||
block, err := aes.NewCipher(encInfo.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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))
|
||||
blockMode.CryptBlocks(origData, crypted)
|
||||
origData = PKCS7UnPadding(origData)
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -8,7 +8,7 @@ require (
|
|||
github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/yapingcat/gomedia v0.0.0-20221023155149-c5f2f0f45ca5
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/text v0.3.3
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -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/yapingcat/gomedia v0.0.0-20221023155149-c5f2f0f45ca5 h1:dswmlgf8sSrjaQJCGDpmI14sIkHqyIZdP6Jwzl7gVDY=
|
||||
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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
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=
|
||||
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=
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue