| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | ''' Decode distribute docs. |
| | |
| | Based on the algorithm described by Changwoo Ryu |
| | See https://groups.google.com/forum/#!topic/hwp-foss/d2KL2ypR89Q |
| | ''' |
| | from __future__ import absolute_import |
| | from __future__ import print_function |
| | from __future__ import unicode_literals |
| | from io import BytesIO |
| | import logging |
| |
|
| | from .plat import get_aes128ecb_decrypt |
| | from .recordstream import read_record |
| | from .tagids import HWPTAG_DISTRIBUTE_DOC_DATA |
| |
|
| | logger = logging.getLogger(__name__) |
| |
|
| |
|
| | def decode(stream): |
| | distdoc_data_record = read_record(stream, 0) |
| | if distdoc_data_record['tagid'] != HWPTAG_DISTRIBUTE_DOC_DATA: |
| | raise IOError('the first record is not an HWPTAG_DISTRIBUTE_DOC_DATA') |
| | distdoc_data = distdoc_data_record['payload'] |
| | key = decode_head_to_key(distdoc_data) |
| | tail = stream.read() |
| | decrypted = decrypt_tail(key, tail) |
| | return BytesIO(decrypted) |
| |
|
| |
|
| | class Random: |
| | ''' MSVC's srand()/rand() like pseudorandom generator. |
| | ''' |
| |
|
| | def __init__(self, seed): |
| | self.seed = seed |
| |
|
| | def rand(self): |
| | self.seed = (self.seed * 214013 + 2531011) & 0xffffffff |
| | value = (self.seed >> 16) & 0x7fff |
| | return value |
| |
|
| |
|
| | def decode_head_to_sha1(record_payload): |
| | ''' Decode HWPTAG_DISTRIBUTE_DOC_DATA. |
| | |
| | It's the sha1 digest of user-supplied password string, i.e., |
| | |
| | '12345' -> hashlib.sha1('12345').digest() |
| | |
| | ''' |
| | if len(record_payload) != 256: |
| | raise ValueError('payload size must be 256 bytes') |
| |
|
| | data = bytearray(record_payload) |
| | seed = data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0] |
| | random = Random(seed) |
| |
|
| | n = 0 |
| | for i in range(256): |
| | if n == 0: |
| | key = random.rand() & 0xff |
| | n = (random.rand() & 0xf) + 1 |
| | if i >= 4: |
| | data[i] = data[i] ^ key |
| | n -= 1 |
| |
|
| | |
| | decoded = data |
| | sha1offset = 4 + (seed & 0xf) |
| |
|
| | ucs16le = decoded[sha1offset:sha1offset + 80] |
| | return ucs16le |
| |
|
| |
|
| | def decode_head_to_key(record_payload): |
| | sha1ucs16le = decode_head_to_sha1(record_payload) |
| | return sha1ucs16le[:16] |
| |
|
| |
|
| | def decrypt_tail(key, encrypted_tail): |
| | decrypt = get_aes128ecb_decrypt() |
| | return decrypt(key, encrypted_tail) |
| |
|