File size: 5,395 Bytes
d94b56e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# -*- coding: utf-8 -*-
#
#   pyhwp : hwp file format parser in python
#   Copyright (C) 2010-2023 mete0r <https://github.com/mete0r>
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from binascii import b2a_hex
from functools import partial
from subprocess import CalledProcessError
from subprocess import Popen
import logging
import os
import subprocess
import tempfile

from . import _lxml
from . import _uno
from . import gir_gsf
from . import javax_transform
from . import jython_poifs
from . import olefileio
from . import xmllint
from . import xsltproc


logger = logging.getLogger(__name__)


def get_xslt():
    if javax_transform.is_enabled():
        return javax_transform.xslt
    if _lxml.is_enabled():
        return _lxml.xslt
    if xsltproc.is_enabled():
        return xsltproc.xslt
    if _uno.is_enabled():
        return _uno.xslt


def get_xslt_compile():
    modules = [
        javax_transform,
        _lxml,
        xsltproc,
        _uno
    ]
    for module in modules:
        if module.is_enabled():
            xslt_compile = getattr(module, 'xslt_compile', None)
            if xslt_compile:
                return xslt_compile
            xslt = getattr(module, 'xslt', None)
            if xslt:
                def xslt_compile(xsl_path):
                    return partial(xslt, xsl_path)


def get_relaxng():
    if _lxml.is_enabled():
        return _lxml.relaxng
    if xmllint.is_enabled():
        return xmllint.relaxng


def get_relaxng_compile():
    modules = [
        _lxml,
        xmllint,
    ]
    for module in modules:
        if module.is_enabled():
            relaxng_compile = getattr(module, 'relaxng_compile', None)
            if relaxng_compile:
                return relaxng_compile
            relaxng = getattr(module, 'relaxng', None)
            if relaxng:
                def relaxng_compile(rng_path):
                    return partial(relaxng, rng_path)


def get_olestorage_class():
    if jython_poifs.is_enabled():
        return jython_poifs.OleStorage
    if olefileio.is_enabled():
        return olefileio.OleStorage
    if _uno.is_enabled():
        return _uno.OleStorage
    if gir_gsf.is_enabled():
        return gir_gsf.OleStorage


def get_aes128ecb_decrypt():
    try:
        return get_aes128ecb_decrypt_cryptography()
    except Exception:
        pass

    try:
        return get_aes128ecb_decrypt_javax()
    except Exception:
        pass

    try:
        return get_aes128ecb_decrypt_openssl()
    except Exception:
        pass

    raise NotImplementedError('aes128ecb_decrypt')


def get_aes128ecb_decrypt_cryptography():
    from cryptography.hazmat.primitives.ciphers import Cipher
    from cryptography.hazmat.primitives.ciphers import algorithms
    from cryptography.hazmat.primitives.ciphers import modes
    from cryptography.hazmat.backends import default_backend

    def decrypt(key, ciphertext):
        backend = default_backend()
        cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend)
        decryptor = cipher.decryptor()
        return decryptor.update(ciphertext) + decryptor.finalize()

    return decrypt


def get_aes128ecb_decrypt_javax():
    from javax.crypto import Cipher
    from javax.crypto.spec import SecretKeySpec

    def decrypt(key, ciphertext):
        secretkey = SecretKeySpec(key, 'AES')
        cipher = Cipher.getInstance('AES/ECB/NoPadding')
        cipher.init(Cipher.DECRYPT_MODE, secretkey)
        decrypted = cipher.doFinal(ciphertext)
        return decrypted.tostring()

    return decrypt


def get_aes128ecb_decrypt_openssl():
    if not openssl_reachable():
        raise NotImplementedError()

    def decrypt(key, ciphertext):
        fd, name = tempfile.mkstemp()
        fp = os.fdopen(fd, 'wb')
        try:
            fp.write(ciphertext)
        finally:
            fp.close()

        args = [
            'openssl',
            'enc',
            '-d',
            '-in',
            name,
            '-aes-128-ecb',
            '-K',
            b2a_hex(key),
            '-nopad',
        ]
        try:
            p = Popen(args, stdout=subprocess.PIPE)
            try:
                return p.stdout.read()
            finally:
                p.wait()
                p.stdout.close()
        finally:
            os.unlink(name)

    return decrypt


def openssl_reachable():
    args = ['openssl', 'version']
    try:
        subprocess.check_output(args)
    except OSError:
        return False
    except CalledProcessError:
        return False
    except Exception as e:
        logger.exception(e)
        return False
    else:
        return True