forked from naksyn/PythonMemoryModule
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcryptmsg.py
More file actions
133 lines (103 loc) · 4.58 KB
/
cryptmsg.py
File metadata and controls
133 lines (103 loc) · 4.58 KB
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
import ctypes
from windows import winproxy
import windows.generated_def as gdef
import windows.crypto
class CryptMessage(gdef.HCRYPTMSG):
"""Represent a PKCS #7 message
(see `Low-level Message Functions <https://msdn.microsoft.com/en-us/library/windows/desktop/aa380252(v=vs.85).aspx#low_level_message_functions>`_)
"""
MSG_PARAM_KNOW_TYPES = {gdef.CMSG_SIGNER_INFO_PARAM: gdef.CMSG_SIGNER_INFO,
gdef.CMSG_SIGNER_COUNT_PARAM: gdef.DWORD,
gdef.CMSG_CERT_COUNT_PARAM: gdef.DWORD,
gdef.CMSG_ENVELOPE_ALGORITHM_PARAM: gdef.CRYPT_ALGORITHM_IDENTIFIER,
gdef.CMSG_RECIPIENT_COUNT_PARAM: gdef.DWORD,
gdef.CMSG_RECIPIENT_INFO_PARAM: gdef.CERT_INFO,
}
def get_param(self, param_type, index=0, raw=False):
data_size = gdef.DWORD()
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa380227(v=vs.85).aspx
winproxy.CryptMsgGetParam(self, param_type, index, None, data_size)
buffer = ctypes.c_buffer(data_size.value)
winproxy.CryptMsgGetParam(self, param_type, index, buffer, data_size)
if raw:
return (buffer, data_size)
if param_type in self.MSG_PARAM_KNOW_TYPES:
buffer = self.MSG_PARAM_KNOW_TYPES[param_type].from_buffer(buffer)
if isinstance(buffer, gdef.DWORD): # DWORD -> return the Python int
return buffer.value
return buffer
# Certificate accessors
@property
def nb_cert(self):
"""The number of certificate embded in the :class:`CryptObject`
:type: :class:`int`
"""
return self.get_param(gdef.CMSG_CERT_COUNT_PARAM)
def get_raw_cert(self, index=0):
return self.get_param(gdef.CMSG_CERT_PARAM, index)
def get_cert(self, index=0):
"""Return embded :class:`Certificate` number ``index``.
.. note::
Not all embded certificate are directly used to sign the :class:`CryptObject`.
"""
return windows.crypto.Certificate.from_buffer(self.get_raw_cert(index))
@property
def certs(self):
"""The list of :class:`Certificate` embded in the message"""
return [self.get_cert(i) for i in range(self.nb_cert)]
# Signers accessors
@property
def nb_signer(self):
"""The number of signers for the CryptObject
:type: :class:`int`
"""
try:
return self.get_param(gdef.CMSG_SIGNER_COUNT_PARAM)
except WindowsError as e:
if (e.winerror & 0xffffffff) == gdef.CRYPT_E_INVALID_MSG_TYPE:
return 0
raise
def get_signer_data(self, index=0):
"""Returns the signer informations for signer nb ``index``
:return: :class:`~windows.generated_def.winstructs.CMSG_SIGNER_INFO`
"""
return self.get_param(gdef.CMSG_SIGNER_INFO_PARAM, index)
@property
def signers(self):
"""The list of :class:`~windows.generated_def.winstructs.CMSG_SIGNER_INFO` embed in the message"""
return [self.get_signer_data(i) for i in range(self.nb_signer)]
@property
def nb_recipient(self):
"""TODO: DOC"""
return self.get_param(gdef.CMSG_RECIPIENT_COUNT_PARAM)
def get_recipient_data(self, index=0):
"""TODO: DOC"""
return self.get_param(gdef.CMSG_RECIPIENT_INFO_PARAM, index)
@property
def recipients(self):
"""TODO: DOC"""
return [self.get_recipient_data(i) for i in range(self.nb_recipient)]
@property
def content(self):
return self.get_param(gdef.CMSG_CONTENT_PARAM)[:]
@property
def content_type(self):
data = self.get_param(gdef.CMSG_INNER_CONTENT_TYPE_PARAM)
assert data[-1] == "\x00", "CMSG_INNER_CONTENT_TYPE_PARAM not NULL TERMINATED"
return data[:-1]
def update(self, blob, final):
# Test isinstance string ?
if isinstance(blob, (windows.pycompat.anybuff, bytearray)):
blob = windows.pycompat.raw_encode(blob)
buffer = windows.utils.BUFFER(gdef.BYTE).from_buffer_copy(blob)
return winproxy.CryptMsgUpdate(self, buffer, len(blob), final)
return winproxy.CryptMsgUpdate(self, blob.pbData, blob.cbData, final)
# constructor
@classmethod
def from_buffer(self, data):
hmsg = winproxy.CryptMsgOpenToDecode(windows.crypto.DEFAULT_ENCODING, 0, 0, None, None, None)
newmsg = CryptMessage(hmsg)
newmsg.update(data, final=True)
return newmsg
def __del__(self):
return winproxy.CryptMsgClose(self)