实现联通 IPTV 认证

#hack

参考中国联通家庭宽带多媒体应用平台技术规范与盒端接口分册。 虽然各地区的实现基本上都仍然是不规范的, 但相比网上的说法已经改了一些地方。

整体流程可以参考这篇文章, 有些流程相对有出入,具体如下。

STB 登录

function getSTBAuthenticator()
{
    document.authform.STBID.value = Authentication.CTCGetConfig("STBID");   
    var EncryptToken = "................................";
    document.authform.Authenticator.value = Authentication.CTCGetAuthInfo(EncryptToken);
    document.authform.userToken.value = "................................";
    document.authform.mac.value = Authentication.CTCGetConfig("mac");
}

这里 CTCGetAuthInfo 仍然是只有 8 位,同样退化成了 DES ,但值的范围可能不一样。 密码的内容可以直接 HMW_config_read("Iptv.Password", pBuf, bufSize);

重新加密的方法:

def des_encrypt_ecb(key, plaintext):
    cipher = DES.new(key, DES.MODE_ECB)
    padded_plaintext = pad(plaintext.encode('utf-8'), DES.block_size)
    encrypted_bytes = cipher.encrypt(padded_plaintext)
    return binascii.hexlify(encrypted_bytes).decode('utf-8')

des_encrypt_ecb(key, f'99999${EncryToken}${UserID}${STBID}${IP}${MAC}$$CTC')

注意这里的 random ,在某些配置下只会用默认值,也就是 99999 ,用随机值反而不对。

tempkey 的算法

md5(hashCode(SESSIONID + 标识符 + MAC地址))

MAC地址加冒号、大写。 标识符是写死的,除非系统升级可能会变。 hashCode 是 Java 同款的 String.hashCode 。

所以计算代码如下:

from hashlib import md5
from functools import reduce
def calc_key(a, c):
    h = lambda s, v=0: reduce(lambda x, y: (x * 31 + ord(y)) & 4294967295, s, v)
    u = h(c, h(a) * 0xcdaa61c1 + 0x870f92bc)
    k = (u + 2**31) % 2**32 - 2**31
    return md5(str(k).encode()).hexdigest().upper()

if __name__ == '__main__':
    session_id = '00000000000000000000000000000000'
    mac_addr = '00:AA:BB:CC:DD:EE'
    print(calc_key(session_id, mac_addr))