orestonce / m3u8d

m3u8视频下载工具, 提供windows/macos图形界面, 下载后自动将ts文件合并、转换格式为mp4
MIT License
690 stars 86 forks source link

crypto/aes: invalid key size 9 #20

Closed benx1n closed 1 year ago

benx1n commented 1 year ago

m3u8链接是这个,我抹去了其中的session_id和media_view_id:m3u8链接 原视频地址是这里:链接 m3u8文件中是存在以下AES-128的key信息 #EXT-X-KEY:METHOD=AES-128,URI="https://hls-auth.cloud.stream.co.jp/key?session_id=123&123" (与上方m3u8中的session_id,media_view_id相同) 如果手动下载key后是可以通过这个项目正确下载TSnilaoda/N_m3u8DL-CLI 但在m3u8d中报了invalid key size 9的错误 如果需要提供详细的session_id和media_view_id可以通过邮件发给您

orestonce commented 1 year ago

收到

orestonce commented 1 year ago

经分析,此网站下载key的url的服务端至少验证了 User-Agent 的 Header信息:

  1. 以下请求能够得到正确的key信息:

    req, err := http.NewRequest(http.MethodGet, `https://hls-auth.cloud.stream.co.jp/key?session_id=b4775a7e-56b8-4d8d-8d12-9ffeef9c7687&media_view_id=6PSgd6HXhgMFUMRL82hcIvisvcAh9e5j`, nil)
    checkErr(err)
    req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36")
    data, err := httputil.DumpRequest(req, false)
    checkErr(err)
    fmt.Println(string(data))
    fmt.Println("===========")
    
    resp, err := http.DefaultClient.Do(req)
    checkErr(err)
    data, err = io.ReadAll(resp.Body)
    checkErr(err)
    fmt.Println(string(data))
  2. 将user-agent的信息改成其他UA,例如 Mozilla/5.0 (iPhone; CPU iPhone OS 10_2 like Mac OS X) AppleWebKit/602.3.12 (KHTML, like Gecko) Mobile/14C92 MicroMessenger/6.5.16 NetType/WIFI Language/zh_CN 以下请求输出Forbiden:

    req, err := http.NewRequest(http.MethodGet, `https://hls-auth.cloud.stream.co.jp/key?session_id=b4775a7e-56b8-4d8d-8d12-9ffeef9c7687&media_view_id=6PSgd6HXhgMFUMRL82hcIvisvcAh9e5j`, nil)
    checkErr(err)
    req.Header.Set("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_2 like Mac OS X) AppleWebKit/602.3.12 (KHTML, like Gecko) Mobile/14C92 MicroMessenger/6.5.16 NetType/WIFI Language/zh_CN")
    data, err := httputil.DumpRequest(req, false)
    checkErr(err)
    fmt.Println(string(data))
    fmt.Println("===========")
    
    resp, err := http.DefaultClient.Do(req)
    checkErr(err)
    data, err = io.ReadAll(resp.Body)
    checkErr(err)
    fmt.Println(string(data))

解决办法, 使用curl 模式,复制 m3u8的url的时候把 Header信息全部带上即可

image screshot_20230531_202508

orestonce commented 1 year ago

可能是session_id 或者 media_view_id 映射过UA信息之类的,具体实现取决于网站的服务端作者。

benx1n commented 1 year ago

ok成功解决了,感谢您的解答

orestonce commented 1 year ago

格式转换还有问题,已经提给对应的开发者

yapingcat commented 1 year ago

@benx1n hello, hls流是你们自己生成的吗

benx1n commented 1 year ago

@benx1n hello, hls流是你们自己生成的吗

是直接在页面上抓到的

yapingcat commented 1 year ago

应该是ts文件解密出问题了 我这边手动解密ts文件,解密出来的ts文件是有pat表的

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "fmt"
    "io/ioutil"
)

func main() {
    ts, e := ioutil.ReadFile("test.ts")
    b, e := ioutil.ReadFile("key")
    fmt.Println("%x", b, len(b), e)
    block, err := aes.NewCipher(b)
    if err != nil {
        fmt.Println(err)
    }
    iv := make([]byte, 16)
    iv[15] = 1
    blockMode := cipher.NewCBCDecrypter(block, iv)
    result := make([]byte, len(ts))
    blockMode.CryptBlocks(result, ts)
    unPadding := int(result[len(result)-1])
    result = result[:len(result)-unPadding]
    ioutil.WriteFile("d_test.ts", result, 0666)
}

解密后的ts文件 d_test.zip

yapingcat commented 1 year ago

https://datatracker.ietf.org/doc/html/rfc8216#section-5.2

An EXT-X-KEY tag with a KEYFORMAT of "identity" that does not have an IV attribute indicates that the Media Sequence Number is to be used as the IV when decrypting a Media Segment, by putting its big-endian binary representation into a 16-octet (128-bit) buffer and padding (on the left) with zeros.

m3u8 文件里面 没有IV ,按照协议需要使用Media Sequence Number

看了m3u8d这块代码,实现上忽略了这块?

orestonce commented 1 year ago

@yapingcat 你说得对,此处是一个bug

orestonce commented 1 year ago

@benx1n 改了,试一下最新版本

benx1n commented 1 year ago

没问题了,可以成功转码成mp4