Skip to content

Commit fa6c66a

Browse files
committed
added tests for encryption functional
1 parent e425329 commit fa6c66a

12 files changed

Lines changed: 259 additions & 28 deletions

File tree

src/xmlsec/constants.pxd

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,21 @@ cdef extern from "xmlsec.h": # xmlsec/strings.h
2424
const_xmlChar* xmlSecNodeObject
2525
const_xmlChar* xmlSecNodeManifest
2626
const_xmlChar* xmlSecNodeSignatureProperties
27+
28+
# Encypted nodes
2729
const_xmlChar* xmlSecNodeEncryptedData
2830
const_xmlChar* xmlSecNodeEncryptedKey
31+
const_xmlChar* xmlSecNodeEncryptionMethod
32+
const_xmlChar* xmlSecNodeEncryptionProperties
33+
const_xmlChar* xmlSecNodeEncryptionProperty
34+
const_xmlChar* xmlSecNodeCipherData
35+
const_xmlChar* xmlSecNodeCipherValue
36+
const_xmlChar* xmlSecNodeCipherReference
37+
const_xmlChar* xmlSecNodeReferenceList
38+
const_xmlChar* xmlSecNodeDataReference
39+
const_xmlChar* xmlSecNodeKeyReference
40+
const_xmlChar* xmlSecNodeKeyInfo
41+
2942

3043
# encryption types
3144
const_xmlChar* xmlSecTypeEncContent

src/xmlsec/constants.pyx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ class Node:
4444
SIGNATURE_PROPERTIES = _u(xmlSecNodeSignatureProperties)
4545
ENCRYPTED_DATA = _u(xmlSecNodeEncryptedData)
4646
ENCRYPTED_KEY = _u(xmlSecNodeEncryptedKey)
47+
ENCRYPTION_METHOD = _u(xmlSecNodeEncryptionMethod)
48+
ENCRYPTION_PROPERTIES = _u(xmlSecNodeEncryptionProperties)
49+
ENCRYPTION_PROPERTY = _u(xmlSecNodeEncryptionProperty)
50+
CIPHER_DATA = _u(xmlSecNodeCipherData)
51+
CIPHER_VALUE = _u(xmlSecNodeCipherValue)
52+
CIPHER_REFERENCE = _u(xmlSecNodeCipherReference)
53+
REFERENCE_LIST = _u(xmlSecNodeReferenceList)
54+
DATA_REFERENCE = _u(xmlSecNodeDataReference)
55+
KEY_REFERENCE = _u(xmlSecNodeKeyReference)
56+
KEY_INFO = _u(xmlSecNodeKeyInfo)
4757

4858

4959
cdef class _Transform:

src/xmlsec/enc.pyx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,11 @@ cdef class EncryptionContext:
4545
cdef xmlSecEncCtxPtr handle = xmlSecEncCtxCreate(_manager)
4646
if handle == NULL:
4747
raise InternalError("failed to create encryption context")
48-
if xmlSecEncCtxInitialize(handle, _manager) < 0:
49-
xmlSecEncCtxDestroy(handle)
50-
raise InternalError("failed to init encryption context")
5148

5249
self._handle = handle
5350

5451
def __dealloc__(self):
5552
if self._handle != NULL:
56-
xmlSecEncCtxFinalize(self._handle)
5753
xmlSecEncCtxDestroy(self._handle)
5854

5955
property key:
@@ -77,13 +73,10 @@ cdef class EncryptionContext:
7773
Note: *template* is modified in place.
7874
"""
7975
cdef int rv
80-
cdef size_t c_size
81-
cdef const_xmlSecByte* c_data
8276

8377
# Data to bytes
84-
text = _b(data)
85-
c_data = <const_xmlSecByte*>text
86-
c_size = len(text)
78+
cdef const_xmlSecByte* c_data = <const_xmlSecByte*>data
79+
cdef size_t c_size = len(data)
8780

8881
with nogil:
8982
rv = xmlSecEncCtxBinaryEncrypt(self._handle, template._c_node, c_data, c_size)

src/xmlsec/template.pyx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ from lxml.includes.etreepublic cimport import_lxml__etree
55
import_lxml__etree()
66

77
from lxml.includes.etreepublic cimport _Element, elementFactory
8-
from lxml.includes.tree cimport const_xmlChar, xmlNode
8+
from lxml.includes.tree cimport const_xmlChar, xmlNode, xmlStrdup
99
from .constants cimport _Transform
1010
from .utils cimport *
1111
from .template cimport *
@@ -111,9 +111,10 @@ def encrypted_data_create(_Element node not None,
111111
id=None,
112112
type=None,
113113
mime_type=None,
114-
encoding=None):
114+
encoding=None,
115+
ns=None):
115116
"""
116-
Creates new <enc:EncryptedData /> node for encryption template.
117+
Creates new <{ns}:EncryptedData /> node for encryption template.
117118
"""
118119
cdef xmlNode* c_node
119120
cdef const_xmlChar* c_id = _b(id)
@@ -124,14 +125,22 @@ def encrypted_data_create(_Element node not None,
124125
c_node = xmlSecTmplEncDataCreate(
125126
node._doc._c_doc, method.target, c_id, c_type, c_mtype, c_encoding)
126127

128+
if ns is not None:
129+
c_node.ns.prefix = xmlStrdup(_b(ns))
127130
return elementFactory(node._doc, c_node)
128131

129132

130-
def encrypted_data_ensure_key_info(_Element node not None, id=None):
133+
def encrypted_data_ensure_key_info(_Element node not None, id=None, ns=None):
134+
"""
135+
Adds <{ns}:KeyInfo/> to the <enc:EncryptedData/> node encNode.
136+
"""
137+
131138
cdef xmlNode* c_node
132139
cdef const_xmlChar* c_id = _b(id)
133140

134141
c_node = xmlSecTmplEncDataEnsureKeyInfo(node._c_node, c_id)
142+
if ns is not None:
143+
c_node.ns.prefix = xmlStrdup(_b(ns))
135144

136145
return elementFactory(node._doc, c_node)
137146

tests/examples/base.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
from os import path
2-
import xmlsec
32
from lxml import etree
43

54
BASE_DIR = path.dirname(__file__)
65

76

87
def parse_xml(name):
98
return etree.parse(path.join(BASE_DIR, name)).getroot()
9+
10+
11+
def compare(name, result):
12+
# Parse the expected file.
13+
xml = parse_xml(name)
14+
15+
# Stringify the root, <Envelope/> nodes of the two documents.
16+
expected_text = etree.tostring(xml, pretty_print=False)
17+
result_text = etree.tostring(result, pretty_print=False)
18+
19+
# Compare the results.
20+
assert expected_text == result_text
21+

tests/examples/enc1-doc.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
XML Security Library example: Original XML doc file for enc example.
4+
-->
5+
<Envelope>
6+
<Data>Hello, World!</Data>
7+
</Envelope>

tests/examples/enc1-res.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Envelope>
3+
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element">
4+
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
5+
<dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
6+
<xenc:EncryptedKey>
7+
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
8+
<xenc:CipherData>
9+
<xenc:CipherValue>UrTgE0UxQa8xevs4SyRA0rsibEz/ZFDjCBD+t4pKSdajB/cefYObZzqq2l41Q6R/
10+
tqYLht5hEBh26AHfjmQSJAL+eChXOt/EaOf63zzJedO90HGqIQyzOeOPURAl3Li8
11+
ivPyLVyocJDeVNeh7W+7kYwpFQ6PLuQxWsFFQXVoRAWbXHpZkSzVheR+5RpYJRTb
12+
1UYXKxu8jg4NqbjucVMDIxUOzsVCDRyk8R8sQrM7D/H/N0y7DAY8oX/WZ45xLwUy
13+
DY/U86tTpTn95NwHD10SLyrL6rpXdbEuoIQHhWLwV9uQxnJA/Pn1KZ+xXK/fePfP
14+
26PBo/hUrN5pm5U8ycc4iw==</xenc:CipherValue>
15+
</xenc:CipherData>
16+
</xenc:EncryptedKey>
17+
</dsig:KeyInfo>
18+
<xenc:CipherData>
19+
<xenc:CipherValue>2pb5Mxd0f+AW56Cs3MfQ9HJkUVeliSi1hVCNCVHTKeMyC2VL6lPhQ9+L01aSeTSY</xenc:CipherValue>
20+
</xenc:CipherData>
21+
</xenc:EncryptedData>
22+
</Envelope>

tests/examples/enc2-res.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Envelope>
3+
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Content" MimeType="binary/octet-stream">
4+
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
5+
<dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
6+
<xenc:EncryptedKey>
7+
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
8+
<xenc:CipherData>
9+
<xenc:CipherValue>HJwrfL7kOIB0QaldMJdza1HitpLCjw+eoult1C6yExDXJ09zKaSQER+pUL9Vt5fm
10+
d4Oitsf0CUNkjG1xWJdFsftqUIuvYGnkUNhT0vtqoYbdhJkCcB9cCwvTrww2+VTF
11+
NIasTdechlSD1qQOR8uf6+S94Ae4PVSfWU+5YLTJFpMjR+OT7f6BSbYNv1By6Cko
12+
G39WTSKTRcVDzcMxRepAGb59r508yKIJhwabCf3Opu+Ams7ia7BH4oa4ro9YSWwm
13+
hAJ0CN4a6b5odcRbNvuHcwWSxpoysWKbOROQ0H4xC4nGZeL/AXlpSc8eNuNG+g6D
14+
CTBwsOXCAEJYXPkTrnB3qQ==</xenc:CipherValue>
15+
</xenc:CipherData>
16+
</xenc:EncryptedKey>
17+
</dsig:KeyInfo>
18+
<xenc:CipherData>
19+
<xenc:CipherValue>4m5BRKEswOe8JISY7NrPGLBYv7Ay5pBV+nG6it51gz0=</xenc:CipherValue>
20+
</xenc:CipherData>
21+
</xenc:EncryptedData>
22+
</Envelope>

tests/examples/test_decrypt.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from os import path
2+
import xmlsec
3+
from .base import parse_xml, BASE_DIR, compare
4+
5+
6+
def test_decrypt1():
7+
manager = xmlsec.KeysManager()
8+
filename = path.join(BASE_DIR, 'rsakey.pem')
9+
key = xmlsec.Key.from_memory(open(filename, 'rb').read(), xmlsec.KeyFormat.PEM, None)
10+
assert key is not None
11+
manager.add_key(key)
12+
13+
enc_ctx = xmlsec.EncryptionContext(manager)
14+
15+
root = parse_xml("enc1-res.xml")
16+
enc_data = xmlsec.tree.find_child(root, "EncryptedData", xmlsec.Namespace.ENC)
17+
assert enc_data is not None
18+
decrypted = enc_ctx.decrypt(enc_data)
19+
assert decrypted.tag == "Data"
20+
21+
compare("enc1-doc.xml", root)
22+
23+
24+
def test_decrypt2():
25+
manager = xmlsec.KeysManager()
26+
filename = path.join(BASE_DIR, 'rsakey.pem')
27+
key = xmlsec.Key.from_memory(open(filename, 'rb').read(), xmlsec.KeyFormat.PEM, None)
28+
assert key is not None
29+
manager.add_key(key)
30+
31+
enc_ctx = xmlsec.EncryptionContext(manager)
32+
33+
root = parse_xml("enc2-res.xml")
34+
enc_data = xmlsec.tree.find_child(root, xmlsec.constants.Node.ENCRYPTED_DATA, xmlsec.Namespace.ENC)
35+
assert enc_data is not None
36+
decrypted = enc_ctx.decrypt(enc_data)
37+
assert decrypted.text == "\ntest\n"

tests/examples/test_encrypt.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
from os import path
2+
import xmlsec
3+
from .base import parse_xml, BASE_DIR
4+
from lxml import etree
5+
6+
7+
def test_encrypt_xml():
8+
# Load the public cert
9+
manager = xmlsec.KeysManager()
10+
filename = path.join(BASE_DIR, 'rsacert.pem')
11+
key = xmlsec.Key.from_memory(open(filename, 'rb').read(), xmlsec.KeyFormat.CERT_PEM, None)
12+
assert key is not None
13+
manager.add_key(key)
14+
template = parse_xml('enc1-doc.xml')
15+
assert template is not None
16+
# Prepare for encryption
17+
enc_data = xmlsec.template.encrypted_data_create(
18+
template, xmlsec.Transform.AES128, type=xmlsec.EncryptionType.ELEMENT, ns="xenc")
19+
20+
xmlsec.template.encrypted_data_ensure_cipher_value(enc_data)
21+
key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig")
22+
enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.Transform.RSA_OAEP)
23+
xmlsec.template.encrypted_data_ensure_cipher_value(enc_key)
24+
25+
data = template.find('./Data')
26+
27+
assert data is not None
28+
# Encrypt!
29+
enc_ctx = xmlsec.EncryptionContext(manager)
30+
enc_ctx.key = xmlsec.Key.generate(xmlsec.KeyData.AES, 128, xmlsec.KeyDataType.SESSION)
31+
enc_data = enc_ctx.encrypt_xml(enc_data, data)
32+
assert enc_data is not None
33+
enc_method = xmlsec.tree.find_child(enc_data, xmlsec.Node.ENCRYPTION_METHOD, xmlsec.Namespace.ENC)
34+
assert enc_method is not None
35+
assert enc_method.get("Algorithm") == "http://www.w3.org/2001/04/xmlenc#aes128-cbc"
36+
key_info = xmlsec.tree.find_child(enc_data, xmlsec.Node.KEY_INFO, xmlsec.Namespace.DS)
37+
assert key_info is not None
38+
enc_method = xmlsec.tree.find_node(key_info, xmlsec.Node.ENCRYPTION_METHOD, xmlsec.Namespace.ENC)
39+
assert enc_method is not None
40+
assert enc_method.get("Algorithm") == "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"
41+
cipher_value = xmlsec.tree.find_node(key_info, xmlsec.Node.CIPHER_VALUE, xmlsec.Namespace.ENC)
42+
assert cipher_value is not None
43+
44+
45+
def test_encrypt_binary():
46+
# Load the public cert
47+
manager = xmlsec.KeysManager()
48+
filename = path.join(BASE_DIR, 'rsacert.pem')
49+
key = xmlsec.Key.from_memory(open(filename, 'rb').read(), xmlsec.KeyFormat.CERT_PEM, None)
50+
assert key is not None
51+
manager.add_key(key)
52+
template = etree.Element("root")
53+
assert template is not None
54+
# Prepare for encryption
55+
enc_data = xmlsec.template.encrypted_data_create(
56+
template, xmlsec.Transform.AES128, type=xmlsec.EncryptionType.CONTENT, ns="xenc",
57+
mime_type="binary/octet-stream")
58+
59+
xmlsec.template.encrypted_data_ensure_cipher_value(enc_data)
60+
key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig")
61+
enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.Transform.RSA_OAEP)
62+
xmlsec.template.encrypted_data_ensure_cipher_value(enc_key)
63+
64+
# Encrypt!
65+
enc_ctx = xmlsec.EncryptionContext(manager)
66+
enc_ctx.key = xmlsec.Key.generate(xmlsec.KeyData.AES, 128, xmlsec.KeyDataType.SESSION)
67+
enc_data = enc_ctx.encrypt_binary(enc_data, b'test')
68+
assert enc_data is not None
69+
assert enc_data.tag == "{%s}%s" % (xmlsec.Namespace.ENC, xmlsec.Node.ENCRYPTED_DATA)
70+
print(xmlsec.Node.ENCRYPTION_METHOD)
71+
enc_method = xmlsec.tree.find_child(enc_data, xmlsec.Node.ENCRYPTION_METHOD, xmlsec.Namespace.ENC)
72+
assert enc_method is not None
73+
assert enc_method.get("Algorithm") == "http://www.w3.org/2001/04/xmlenc#aes128-cbc"
74+
key_info = xmlsec.tree.find_child(enc_data, xmlsec.Node.KEY_INFO, xmlsec.Namespace.DS)
75+
assert key_info is not None
76+
enc_method = xmlsec.tree.find_node(key_info, xmlsec.Node.ENCRYPTION_METHOD, xmlsec.Namespace.ENC)
77+
assert enc_method is not None
78+
assert enc_method.get("Algorithm") == "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"
79+
cipher_value = xmlsec.tree.find_node(key_info, xmlsec.Node.CIPHER_VALUE, xmlsec.Namespace.ENC)
80+
assert cipher_value is not None

0 commit comments

Comments
 (0)