Files
douyin_video_download/douyin/crypto.py
whale-fall-code 2bb83f3685 初始提交:抖音视频批量采集流水线
App 端免签名接口(设备注册 + detail + CDN 直链),一体化流水线
下载→抽音→传COS→记录→删本地,AI 作品四档判定,四份文档:
README(使用指南)、PROGRESS(批次进度)、RE(逆向全过程)、AI(判定规则)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 16:31:10 +08:00

180 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""a_bogus 依赖的底层密码学原语:SM3、RC4、自定义 Base64。
这三样都是公开算法,与抖音无关,可以独立验证正确性:
- SM3 见 GB/T 32905-2016,本文件底部带官方测试向量自检
- RC4 标准流密码
- 自定义 Base64 只是把标准码表换成抖音自己那套字符顺序
"""
from __future__ import annotations
from typing import Iterable, List, Sequence
# --------------------------------------------------------------------------- #
# SM3
# --------------------------------------------------------------------------- #
_IV = [
0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600,
0xA96F30BC, 0x163138AA, 0xE38DEE4D, 0xB0FB0E4E,
]
_MASK = 0xFFFFFFFF
def _rotl(x: int, n: int) -> int:
n &= 31
return ((x << n) | (x >> (32 - n))) & _MASK
def _ff(j: int, x: int, y: int, z: int) -> int:
return (x ^ y ^ z) if j < 16 else ((x & y) | (x & z) | (y & z))
def _gg(j: int, x: int, y: int, z: int) -> int:
return (x ^ y ^ z) if j < 16 else ((x & y) | ((~x & _MASK) & z))
def _p0(x: int) -> int:
return x ^ _rotl(x, 9) ^ _rotl(x, 17)
def _p1(x: int) -> int:
return x ^ _rotl(x, 15) ^ _rotl(x, 23)
def _cf(v: Sequence[int], block: bytes) -> List[int]:
"""压缩函数 CF(V, B)。"""
w = [int.from_bytes(block[i * 4:i * 4 + 4], "big") for i in range(16)]
for j in range(16, 68):
w.append(
_p1(w[j - 16] ^ w[j - 9] ^ _rotl(w[j - 3], 15))
^ _rotl(w[j - 13], 7)
^ w[j - 6]
)
w1 = [w[j] ^ w[j + 4] for j in range(64)]
a, b, c, d, e, f, g, h = v
for j in range(64):
t = 0x79CC4519 if j < 16 else 0x7A879D8A
ss1 = _rotl((_rotl(a, 12) + e + _rotl(t, j)) & _MASK, 7)
ss2 = ss1 ^ _rotl(a, 12)
tt1 = (_ff(j, a, b, c) + d + ss2 + w1[j]) & _MASK
tt2 = (_gg(j, e, f, g) + h + ss1 + w[j]) & _MASK
d = c
c = _rotl(b, 9)
b = a
a = tt1
h = g
g = _rotl(f, 19)
f = e
e = _p0(tt2)
return [x ^ y for x, y in zip(v, (a, b, c, d, e, f, g, h))]
def sm3(data: bytes) -> bytes:
"""SM3 摘要,返回 32 字节。"""
bit_len = len(data) * 8
padded = data + b"\x80"
padded += b"\x00" * ((56 - len(padded) % 64) % 64)
padded += bit_len.to_bytes(8, "big")
v = list(_IV)
for i in range(0, len(padded), 64):
v = _cf(v, padded[i:i + 64])
return b"".join(x.to_bytes(4, "big") for x in v)
def sm3_to_list(data: bytes | Iterable[int]) -> List[int]:
"""SM3 摘要,返回 32 个 int(a_bogus 内部按字节数组传递)。"""
if not isinstance(data, (bytes, bytearray)):
data = bytes(bytearray(data))
return list(sm3(bytes(data)))
# --------------------------------------------------------------------------- #
# RC4
# --------------------------------------------------------------------------- #
def rc4(key: bytes, data: bytes) -> bytes:
"""标准 RC4。加解密同一函数。"""
s = list(range(256))
j = 0
klen = len(key)
for i in range(256):
j = (j + s[i] + key[i % klen]) & 0xFF
s[i], s[j] = s[j], s[i]
out = bytearray(len(data))
i = j = 0
for n, ch in enumerate(data):
i = (i + 1) & 0xFF
j = (j + s[i]) & 0xFF
s[i], s[j] = s[j], s[i]
out[n] = ch ^ s[(s[i] + s[j]) & 0xFF]
return bytes(out)
# --------------------------------------------------------------------------- #
# 自定义码表 Base64
# --------------------------------------------------------------------------- #
STD_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
def b64_encode(data: bytes, alphabet: str, pad: bool = True) -> str:
"""按给定 64(+1) 字符码表做 Base64 编码。
alphabet 长度为 64 时不补位;为 65 时最后一位作为填充字符。
"""
if len(alphabet) not in (64, 65):
raise ValueError(f"码表长度必须是 64 或 65,收到 {len(alphabet)}")
fill = alphabet[64] if len(alphabet) == 65 else ""
out: List[str] = []
for i in range(0, len(data), 3):
chunk = data[i:i + 3]
n = int.from_bytes(chunk + b"\x00" * (3 - len(chunk)), "big")
quad = [alphabet[(n >> shift) & 0x3F] for shift in (18, 12, 6, 0)]
keep = len(chunk) + 1 # 1字节->2字符, 2字节->3字符, 3字节->4字符
out.extend(quad[:keep])
if pad and fill:
out.extend(fill * (4 - keep))
return "".join(out)
# --------------------------------------------------------------------------- #
# 自检
# --------------------------------------------------------------------------- #
# GB/T 32905-2016 附录 A 给出的两组标准测试向量
_SM3_VECTORS = [
(b"abc",
"66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0"),
(b"abcd" * 16,
"debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732"),
]
def self_test() -> None:
"""跑通即说明 SM3/RC4/Base64 实现无误。"""
for msg, want in _SM3_VECTORS:
got = sm3(msg).hex()
assert got == want, f"SM3({msg[:8]!r}...) = {got}, 期望 {want}"
# RC4 官方测试向量:key="Key", plaintext="Plaintext" -> BBF316E8D940AF0AD3
assert rc4(b"Key", b"Plaintext").hex().upper() == "BBF316E8D940AF0AD3"
# 用标准码表时,自定义 Base64 应与 base64 模块完全一致
import base64
import os
for n in range(1, 40):
raw = os.urandom(n)
assert b64_encode(raw, STD_ALPHABET) == base64.b64encode(raw).decode()
print("crypto self-test OK: SM3 / RC4 / custom-base64 均通过")
if __name__ == "__main__":
self_test()