|
| 1 | +import re |
| 2 | +import sys |
| 3 | +from random import randint |
| 4 | +from typing import List |
| 5 | + |
| 6 | +from cryptography.hazmat.backends import default_backend |
| 7 | +from cryptography.hazmat.primitives.asymmetric import dsa |
| 8 | +from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature |
| 9 | +from cryptography.hazmat.primitives.hashes import SHA1 |
| 10 | + |
| 11 | + |
| 12 | +def construct_key(*, p, q, g, y, x) -> dsa.DSAPrivateKey: |
| 13 | + params = dsa.DSAParameterNumbers(p, q, g) |
| 14 | + pub = dsa.DSAPublicNumbers(y, params) |
| 15 | + priv = dsa.DSAPrivateNumbers(x, pub) |
| 16 | + return priv.private_key(backend=default_backend()) |
| 17 | + |
| 18 | + |
| 19 | +def sign(k: dsa.DSAPrivateKey, m: str) -> str: |
| 20 | + """P1363 format sig over m as a string of hex digits""" |
| 21 | + assert k.key_size == 1024 |
| 22 | + sig = k.sign(m.encode(), SHA1()) |
| 23 | + r, s = decode_dss_signature(sig) |
| 24 | + return "{:040X}{:040X}".format(r, s) |
| 25 | + |
| 26 | + |
| 27 | +def fix_group_checksum(group_number: int, n: int) -> int: |
| 28 | + checksum = n >> 4 & 0xf ^ \ |
| 29 | + n >> 5 & 0x8 ^ \ |
| 30 | + n >> 9 & 0x7 ^ \ |
| 31 | + n >> 11 & 0xe ^ \ |
| 32 | + n >> 15 & 0x1 ^ \ |
| 33 | + group_number |
| 34 | + return n & 0xfff0 | checksum |
| 35 | + |
| 36 | + |
| 37 | +def overall_checksum(groups: List[int]) -> int: |
| 38 | + r = 0 |
| 39 | + for i in range(20): |
| 40 | + g, digit = divmod(i, 4) |
| 41 | + v = groups[g] >> (digit * 8) & 0xff |
| 42 | + # v is lowbyte, highbyte, 0, 0 in turn for each group |
| 43 | + r ^= v << 8 |
| 44 | + for _ in range(8): |
| 45 | + r <<= 1 |
| 46 | + if r & 0x10000: |
| 47 | + r ^= 0x8005 |
| 48 | + return r & 0xffff |
| 49 | + |
| 50 | + |
| 51 | +def random_serial(): |
| 52 | + """ |
| 53 | + 3xxc-xxxc-xxxc-xxxc-xxxc-dddd |
| 54 | + x is random |
| 55 | + c is a checksum over each group |
| 56 | + d is a checksum over all groups |
| 57 | + """ |
| 58 | + groups = [randint(0x3000, 0x3fff), |
| 59 | + randint(0x0000, 0xffff), |
| 60 | + randint(0x0000, 0xffff), |
| 61 | + randint(0x0000, 0xffff), |
| 62 | + randint(0x0000, 0xffff)] |
| 63 | + for i in range(5): |
| 64 | + groups[i] = fix_group_checksum(i, groups[i]) |
| 65 | + d = overall_checksum(groups) |
| 66 | + return "{:04X}-{:04X}-{:04X}-{:04X}-{:04X}-{:04X}".format(*groups, d) |
| 67 | + |
| 68 | + |
| 69 | +def generate_single(k: dsa.DSAPrivateKey, id1: int, id2: int, hwid: str) -> str: |
| 70 | + f = "{},{:02X},{:02X},Standard,{}" |
| 71 | + serial = random_serial() |
| 72 | + msg = f.format(serial, id1, id2, hwid) |
| 73 | + sig = sign(k, msg) |
| 74 | + return f.format(serial, id1, id2, sig) |
| 75 | + |
| 76 | + |
| 77 | +def generate_all(k: dsa.DSAPrivateKey, hwid: str) -> str: |
| 78 | + yield generate_single(k, 0x0, 0xa0, hwid) |
| 79 | + for i in range(0x40, 0xff + 1): |
| 80 | + yield generate_single(k, i, 0x10, hwid) |
| 81 | + for i in range(0x8000, 0x80ff + 1): |
| 82 | + yield generate_single(k, i, 0x10, hwid) |
| 83 | + |
| 84 | + |
| 85 | +team_r2r_key = construct_key( |
| 86 | + p=0xbab5a10970f083e266a1252897daac1d67374712e79d3df1bc8c08a3493c6aa9a2ff33be4513d8b6767ab6aae2af6cc9107976fa75fee134e8b7be03d78cc64e089c845207d306a6035f172c5b750275f00bd3ca2331b8a59d54fe79393854dd884b8d334d553b38bc5e886c0a2dd0e4ec32f7d88de1a7c9df5c424ee7b1ce6d, |
| 87 | + q=0xc37be90e3f8e64e03a42ca8d68ad5c83eb47d3a9, |
| 88 | + g=0xa33c8737f42e2516a1525544e611d71295805ced94d260d5777db976f6721f52479158e2477efb0ea6ff30d34d15b23669f0967d29a2c746288ee42c8d91fe4dbe79a73ee8831251a3566864858e589adcd41c3863ea118fbbcdf34bd64ef0e7ae20b00192709a8346c816b54a51d804a6e06fce1da4b043c2b5270d4e441622, |
| 89 | + y=0x33fd12fd459fe6c5c1bc0991e915f8bf49997716bde5c3bdf9a096bdcbf7a425ef6a495683cc84f3dafab7a1d5cf9f377fda84c042e47e7c608298c6917a3caab40b3c6262559fe699091c5bb6ac8de01f0a9f887c739ffa3a1a858000f85a1811ec33a2190063341e8c20aba068b90383f8ca27d30aa89adf40de9ce735dedb, |
| 90 | + x=0xc369ea757b46484d1df3819cc4183f6f9a9bcf3c |
| 91 | +) |
| 92 | + |
| 93 | +assert len(sys.argv) == 2, "Expected hardware ID as command line argument" |
| 94 | +hwid = sys.argv[1].upper() |
| 95 | +assert re.fullmatch(r"([0-9A-F]{4}-){5}[0-9A-F]{4}", hwid), "Expected hardware ID like 1111-1111-1111-1111-1111-1111" |
| 96 | + |
| 97 | +for line in generate_all(team_r2r_key, hwid): |
| 98 | + print(line) |
0 commit comments