|
|
<?php
// ysp.php?cnlid=XXX&livepid=YYY&defn=auto
function randomHexStr($len) {
$chars = '0123456789ABCDEF';
$str = '';
for ($i = 0; $i < $len; $i++) {
$str .= $chars[rand(0, 15)];
}
return $str;
}
function calcSignature($data) {
$sig = 0;
for ($i = 0; $i < strlen($data); $i++) {
$sig = (0x83 * $sig + ord($data[$i])) & 0x7FFFFFFF;
}
return $sig;
}
function xorArray($data, $key) {
$out = '';
$len = strlen($data);
for ($i = 0; $i < $len; $i++) {
$out .= chr(ord($data[$i]) ^ $key[$i % count($key)]);
}
return $out;
}
// 自定义 Base64 编码(-_= 替代 +/=)
function customEncode($data) {
$b64 = base64_encode($data);
return str_replace(['+', '/', '='], ['-', '_', ''], $b64);
}
// ====== TEA 加密(ECB 模式)======
function teaEncryptECB($plain, $key) {
// plain: 8 bytes, key: 16 bytes
if (strlen($plain) != 8 || strlen($key) != 16) return false;
[$y, $z] = array_values(unpack('N2', $plain));
$k = array_values(unpack('N4', $key));
$delta = 0x9e3779b9;
$sum = 0;
for ($i = 0; $i < 16; $i++) {
$sum = ($sum + $delta) & 0xffffffff;
$y = ($y + ((($z << 4) & 0xffffffff) + $k[0]) ^ ($z + $sum) ^ (($z >> 5) + $k[1])) & 0xffffffff;
$z = ($z + ((($y << 4) & 0xffffffff) + $k[2]) ^ ($y + $sum) ^ (($y >> 5) + $k[3])) & 0xffffffff;
}
return pack('N2', $y, $z);
}
// ====== oi_symmetry_encrypt2 (TEA-CBC with padding) ======
function oiSymmetryEncrypt2($input, $key) {
$bodyLen = strlen($input);
$padSaltZero = 1 + 2 + 7; // PadLen(1) + Salt(2) + Zero(7)
$total = $bodyLen + $padSaltZero;
$padLen = (8 - ($total % 8)) % 8;
$fullLen = $total + $padLen;
// 构造明文块: [PadLen][Padding][Salt][Body][Zero]
$plain = chr($padLen & 0x07); // 最低3位存 padLen
for ($i = 0; $i < $padLen; $i++) {
$plain .= chr(rand(0, 255));
}
for ($i = 0; $i < 2; $i++) {
$plain .= chr(rand(0, 255)); // Salt
}
$plain .= $input;
for ($i = 0; $i < 7; $i++) {
$plain .= "\x00"; // Zero
}
// 分块加密(CBC 模式,IV=0)
$cipher = '';
$iv = str_repeat("\x00", 8);
$prevPlain = str_repeat("\x00", 8);
for ($i = 0; $i < strlen($plain); $i += 8) {
$block = substr($plain, $i, 8);
if (strlen($block) < 8) $block = str_pad($block, 8, "\x00");
// XOR with previous cipher (CBC)
$xorBlock = '';
for ($j = 0; $j < 8; $j++) {
$xorBlock .= chr(ord($block[$j]) ^ ord($iv[$j]));
}
$encrypted = teaEncryptECB($xorBlock, $key);
// XOR with previous plain (as in original code)
$finalBlock = '';
for ($j = 0; $j < 8; $j++) {
$finalBlock .= chr(ord($encrypted[$j]) ^ ord($prevPlain[$j]));
}
$cipher .= $finalBlock;
$prevPlain = $block;
$iv = $finalBlock;
}
return $cipher;
}
// ====== ckey42 ======
function generateCkey($platform, $timestamp, $sdtfrom, $vid, $guid, $appVer) {
$header = hex2bin('0000004200000004000004d2');
$randFlag = base64_encode(random_bytes(18));
// 构建结构(按顺序拼接)
$buffer = $header;
$buffer .= pack('N', $platform);
$buffer .= "\x00\x00\x00\x00"; // signature placeholder
$buffer .= pack('N', $timestamp);
$buffer .= pack('n', strlen($sdtfrom)) . $sdtfrom;
$buffer .= pack('n', strlen($randFlag)) . $randFlag;
$buffer .= pack('n', strlen($appVer)) . $appVer;
$buffer .= pack('n', strlen($vid)) . $vid;
$buffer .= pack('n', strlen($guid)) . $guid;
$buffer .= pack('N', 1); // part1
$buffer .= pack('N', 1); // isDlna
$buffer .= pack('n', 9) . "2622783A";
$buffer .= pack('n', 3) . "nil";
$uuid4 = strtolower(sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
));
$buffer .= pack('n', strlen($uuid4)) . $uuid4;
$buffer .= pack('n', 3) . "nil";
$buffer .= pack('n', 7) . "v0.1.000";
$buffer .= pack('n', 33) . "com.cctv.yangshipin.app.iphone";
$buffer .= pack('n', strlen((string)$platform)) . (string)$platform;
$buffer .= pack('n', 12) . "ex_json_bus";
$buffer .= pack('n', 12) . "ex_json_vs";
$buffer .= pack('n', 66) . randomHexStr(66);
// 前缀长度(2字节大端)
$len = strlen($buffer);
$fullBuffer = pack('n', $len) . $buffer;
// 加密
$teaKey = hex2bin('59b2f7cf725ef43c34fdd7c123411ed3');
$encrypted = oiSymmetryEncrypt2($fullBuffer, $teaKey);
// 添加 checksum
$checksum = calcSignature($fullBuffer);
$encrypted .= pack('N', $checksum);
// XOR
$xorKey = [0x84, 0x2E, 0xED, 0x08, 0xF0, 0x66, 0xE6, 0xEA,
0x48, 0xB4, 0xCA, 0xA9, 0x91, 0xED, 0x6F, 0xF3];
$xored = xorArray($encrypted, $xorKey);
return "--01" . customEncode($xored);
}
// ====== 主逻辑 ======
if (!isset($_GET['cnlid']) || !isset($_GET['livepid'])) {
die("Missing cnlid or livepid");
}
$cnlid = $_GET['cnlid'];
$livepid = $_GET['livepid'];
$defn = $_GET['defn'] ?? 'auto';
$params = [
'atime' => '120',
'livepid' => $livepid,
'cnlid' => $cnlid,
'appVer' => 'V8.22.1035.3031',
'app_version' => '300090',
'caplv' => '1',
'cmd' => '2',
'defn' => $defn,
'device' => 'iPhone',
'encryptVer' => '4.2',
'getpreviewinfo' => '0',
'hevclv' => '33',
'lang' => 'zh-Hans_JP',
'livequeue' => '0',
'logintype' => '1',
'nettype' => '1',
'newnettype' => '1',
'newplatform' => '4330403',
'platform' => '4330403',
'playbacktime' => '0',
'sdtfrom' => 'v3021',
'spacode' => '23',
'spaudio' => '1',
'spdemuxer' => '6',
'spdrm' => '2',
'spdynamicrange' => '7',
'spflv' => '1',
'spflvaudio' => '1',
'sphdrfps' => '60',
'sphttps' => '0',
'spvcode' => 'MSgzMDoyMTYwLDYwOjIxNjB8MzA6MjE2MCw2MDoyMTYwKTsyKDMwOjIxNjAsNjA6MjE2MHwzMDoyMTYwLDYwOjIxNjAp',
'spvideo' => '4',
'stream' => '1',
'system' => '1',
'sysver' => 'ios18.2.1',
'uhd_flag' => '4',
];
$Platform = 4330403;
$Timestamp = time();
$StaGuid = randomHexStr(32);
$sdtfrom = 'dcgh';
$cKey = generateCkey($Platform, $Timestamp, $sdtfrom, $cnlid, $StaGuid, $params['appVer']);
$params['cKey'] = $cKey;
$url = "https://liveinfo.ysp.cctv.cn?" . http_build_query($params);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'qqlive');
curl_setopt($ch, CURLOPT_ENCODING, 'gzip');
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
if (isset($data['error'])) {
die("Error: " . json_encode($data));
}
if ($defn === 'auto' && isset($data['formats'])) {
header('Content-Type: application/json');
echo json_encode(['formats' => $data['formats']]);
} else {
if (isset($data['playurl'])) {
header("Location: " . $data['playurl']);
exit;
} else {
die("No playurl found");
}
}
?> |
|