2
* xmlenc.cpp - XML Encryption
3
* Copyright (C) 2003 Justin Karneges
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
#include"../util/bytestream.h"
24
#include"../util/base64.h"
27
static QByteArray nodeToArray(const QDomNode &e)
30
QTextStream ts(&out, IO_WriteOnly);
32
QCString xmlToEnc = out.utf8();
33
int len = xmlToEnc.length();
35
memcpy(b.data(), xmlToEnc.data(), len);
39
static QDomElement findSubTag(const QDomElement &e, const QString &name, bool *found)
44
for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
45
QDomElement i = n.toElement();
48
if(i.tagName() == name) {
60
using namespace XmlEnc;
63
//----------------------------------------------------------------------------
65
//----------------------------------------------------------------------------
74
bool KeyInfo::isEmpty() const
76
if(v_name.isEmpty() && v_value.isEmpty() && v_rmethods.isEmpty() && v_key.isNull())
81
QString KeyInfo::name() const
86
QByteArray KeyInfo::value () const
91
QStringList KeyInfo::retrievalMethods() const
96
QDomElement KeyInfo::encryptedKey() const
101
void KeyInfo::setName(const QString &s)
106
void KeyInfo::setValue(const QByteArray &d)
111
void KeyInfo::setRetrievalMethods(const QStringList &s)
116
void KeyInfo::attachEncryptedKey(const QDomElement &e)
121
QDomElement KeyInfo::toXml(QDomDocument *doc) const
123
QDomElement e = doc->createElement("ds:KeyInfo");
124
e.setAttribute("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#");
126
if(!v_value.isEmpty()) {
127
QDomElement v = doc->createElement("ds:KeyValue");
128
v.appendChild(doc->createTextNode(Base64::arrayToString(v_value)));
132
if(!v_name.isEmpty()) {
133
QDomElement n = doc->createElement("ds:KeyName");
134
n.appendChild(doc->createTextNode(v_name));
138
for(QStringList::ConstIterator it = v_rmethods.begin(); it != v_rmethods.end(); ++it) {
139
QDomElement r = doc->createElement("ds:RetrievalMethod");
140
r.setAttribute("Type", "http://www.w3.org/2001/04/xmlenc#EncryptedKey");
141
r.setAttribute("URI", *it);
146
e.appendChild(v_key);
151
bool KeyInfo::fromXml(const QDomElement &e)
153
if(e.tagName() != "ds:KeyInfo" || e.attribute("xmlns:ds") != "http://www.w3.org/2000/09/xmldsig#")
164
i = findSubTag(e, "ds:KeyValue", &found);
166
val = Base64::stringToArray(i.text());
167
i = findSubTag(e, "ds:KeyName", &found);
170
QDomNodeList l = e.elementsByTagName("ds:RetrievalMethod");
171
for(int n = 0; n < (int)l.count(); ++n) {
172
QDomElement r = l.item(n).toElement();
173
if(r.attribute("Type") == "http://www.w3.org/2001/04/xmlenc#EncryptedKey")
174
rml += r.attribute("URI");
176
i = findSubTag(e, "EncryptedKey", &found);
190
//----------------------------------------------------------------------------
191
// EncryptionProperty
192
//----------------------------------------------------------------------------
193
EncryptionProperty::EncryptionProperty(const QString &target, const QString &id)
199
QString EncryptionProperty::target() const
204
QString EncryptionProperty::id() const
209
QString EncryptionProperty::property(const QString &var) const
211
QStringList::ConstIterator it = vars.begin();
212
QStringList::ConstIterator it2 = vals.begin();
213
while(it != vars.end()) {
222
void EncryptionProperty::setTarget(const QString &target)
227
void EncryptionProperty::setId(const QString &id)
232
void EncryptionProperty::setProperty(const QString &var, const QString &val)
234
if(var == "Target" || var == "Id")
237
// see if we have it already
238
QStringList::Iterator it = vars.begin();
239
QStringList::Iterator it2 = vals.begin();
240
while(it != vars.end()) {
253
QDomElement EncryptionProperty::toXml(QDomDocument *doc) const
255
QDomElement e = doc->createElement("EncryptionProperty");
256
if(!v_target.isEmpty())
257
e.setAttribute("Target", v_target);
259
e.setAttribute("Id", v_id);
261
QStringList::ConstIterator it = vars.begin();
262
QStringList::ConstIterator it2 = vals.begin();
263
while(it != vars.end()) {
264
e.setAttribute(*it, *it2);
272
bool EncryptionProperty::fromXml(QDomElement &e)
274
if(e.tagName() != "EncryptionProperty")
277
v_target = e.attribute("Target");
278
v_id = e.attribute("Id");
281
QDomNamedNodeMap map = e.attributes();
282
for(int n = 0; n < (int)map.count(); ++n) {
283
QDomAttr a = map.item(n).toAttr();
284
QString n = a.name();
285
if(n == "Target" || n == "Id")
295
//----------------------------------------------------------------------------
296
// EncryptionProperties
297
//----------------------------------------------------------------------------
298
EncryptionProperties::EncryptionProperties(const QString &s)
299
:QValueList<EncryptionProperty>()
304
QString EncryptionProperties::id() const
309
void EncryptionProperties::setId(const QString &s)
314
QDomElement EncryptionProperties::toXml(QDomDocument *doc) const
316
QDomElement e = doc->createElement("EncryptionProperties");
318
e.setAttribute("Id", v_id);
319
for(QValueList<EncryptionProperty>::ConstIterator it = begin(); it != end(); ++it) {
320
const EncryptionProperty &p = *it;
321
e.appendChild(p.toXml(doc));
326
bool EncryptionProperties::fromXml(QDomElement &e)
328
if(e.tagName() != "EncryptionProperties")
332
v_id = e.attribute("Id");
333
QDomNodeList l = e.elementsByTagName("EncryptionProperty");
334
for(int n = 0; n < (int)l.count(); ++n) {
335
QDomElement r = l.item(n).toElement();
336
EncryptionProperty p;
346
//----------------------------------------------------------------------------
348
//----------------------------------------------------------------------------
349
Encrypted::Encrypted()
351
baseNS = "http://www.w3.org/2001/04/xmlenc#";
355
Encrypted::~Encrypted()
360
void Encrypted::clear()
364
v_dataType = Arbitrary;
367
v_keyInfo = KeyInfo();
370
v_cref = Reference();
374
Method Encrypted::cipherTypeToMethod(Cipher::Type t) const
376
if(t == Cipher::TripleDES)
378
else if(t == Cipher::AES_128)
380
else if(t == Cipher::AES_256)
386
void Encrypted::setDataReference(const Reference &cref, Method m)
392
bool Encrypted::encryptData(const QByteArray &data, const Cipher::Key &key)
394
QByteArray iv = Cipher::generateIV(key.type());
395
if(!sym_encrypt(data, key, iv, &v_cval))
397
v_dataType = Arbitrary;
398
v_method = cipherTypeToMethod(key.type());
402
bool Encrypted::encryptElement(const QDomElement &data, const Cipher::Key &key)
404
QByteArray iv = Cipher::generateIV(key.type());
405
if(!sym_encrypt(nodeToArray(data), key, iv, &v_cval))
408
v_dataType = Element;
409
v_method = cipherTypeToMethod(key.type());
413
bool Encrypted::encryptContent(const QDomElement &data, const Cipher::Key &key)
415
// convert children to raw data
417
for(QDomNode n = data.firstChild(); !n.isNull(); n = n.nextSibling())
418
ByteStream::appendArray(&a, nodeToArray(n));
420
QByteArray iv = Cipher::generateIV(key.type());
421
if(!sym_encrypt(a, key, iv, &v_cval))
424
v_dataType = Content;
425
v_method = cipherTypeToMethod(key.type());
429
bool Encrypted::encryptKey(const Cipher::Key &data, const Cipher::Key &key)
431
if(!sym_keywrap(data.data(), key, &v_cval))
434
v_dataType = Arbitrary;
435
v_method = cipherTypeToMethod(key.type());
439
bool Encrypted::encryptKey(const Cipher::Key &data, const RSAKey &key)
442
if(data.type() == Cipher::TripleDES)
450
result = encryptRSA2(data.data(), key, &ok);
452
result = encryptRSA(data.data(), key, &ok);
457
v_dataType = Arbitrary;
458
v_method = useOAEP ? RSA_OAEP : RSA_1_5;
459
v_cval = Base64::arrayToString(result);
463
QByteArray Encrypted::decryptData(const Cipher::Key &key) const
466
if(!sym_decrypt(v_cval, key, &result))
471
QDomElement Encrypted::decryptElement(QDomDocument *doc, const Cipher::Key &key) const
474
if(!sym_decrypt(v_cval, key, &result))
475
return QDomElement();
478
if(!d.setContent(result))
479
return QDomElement();
480
return doc->importNode(d.documentElement(), true).toElement();
483
QDomNodeList Encrypted::decryptContent(QDomDocument *doc, const Cipher::Key &key) const
486
if(!sym_decrypt(v_cval, key, &result))
487
return QDomNodeList();
490
result.resize(result.size()+1);
491
result[result.size()-1] = 0;
493
QCString cs = "<dummy>";
494
cs += (char *)result.data();
498
if(!d.setContent(cs))
499
return QDomNodeList();
500
QDomElement e = d.documentElement().firstChild().toElement();
501
if(e.isNull() || e.tagName() != "dummy")
502
return QDomNodeList();
504
return doc->importNode(e, true).childNodes();
507
QByteArray Encrypted::decryptKey(const Cipher::Key &key) const
510
if(!sym_keyunwrap(v_cval, key, &result))
516
QByteArray Encrypted::decryptKey(const RSAKey &key) const
518
QByteArray data = Base64::stringToArray(v_cval);
521
if(v_method == RSA_OAEP)
522
result = decryptRSA2(data, key, &ok);
524
result = decryptRSA(data, key, &ok);
531
QDomElement Encrypted::toXml(QDomDocument *doc) const
533
QString baseNS = "http://www.w3.org/2001/04/xmlenc#";
538
enc = doc->createElement("EncryptedData");
540
enc = doc->createElement("EncryptedKey");
541
enc.setAttribute("xmlns", baseNS);
543
enc.setAttribute("Id", v_id);
545
enc.setAttribute("Type", baseNS + "Element");
548
QDomElement meth = doc->createElement("EncryptionMethod");
549
meth.setAttribute("Algorithm", methodToAlgorithm(v_method, v_type));
550
if(v_method == RSA_OAEP) {
552
QDomElement dm = doc->createElement("ds:DigestMethod");
553
dm.setAttribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
554
meth.appendChild(dm);
556
enc.appendChild(meth);
559
if(!v_keyInfo.isEmpty())
560
enc.appendChild(v_keyInfo.toXml(doc));
563
QDomElement cd = doc->createElement("CipherData");
564
if(!v_cref.uri().isEmpty()) {
565
QDomElement cr = doc->createElement("CipherReference");
566
cr.setAttribute("URI", v_cref.uri());
567
if(!v_cref.transforms().isNull())
568
cr.appendChild(v_cref.transforms());
572
QDomElement cv = doc->createElement("CipherValue");
573
cv.appendChild(doc->createTextNode(v_cval));
578
// encryption properties
579
if(!v_props.isEmpty())
580
enc.appendChild(v_props.toXml(doc));
583
if(!v_reflist.isEmpty()) {
584
QDomElement e = doc->createElement("ReferenceList");
585
for(QValueList<Reference>::ConstIterator it = v_reflist.begin(); it != v_reflist.end(); ++it) {
586
const Reference &r = *it;
587
QDomElement df = doc->createElement("DataReference");
588
df.setAttribute("URI", r.uri());
589
if(!r.transforms().isNull())
590
df.appendChild(r.transforms());
597
if(!v_carrykeyname.isEmpty()) {
598
QDomElement e = doc->createElement("CarriedKeyName");
599
e.appendChild(doc->createTextNode(v_carrykeyname));
606
bool Encrypted::fromXml(const QDomElement &e)
608
QString baseNS = "http://www.w3.org/2001/04/xmlenc#";
609
if(e.attribute("xmlns") != baseNS)
611
DataType dt = Arbitrary;
612
if(e.hasAttribute("Type")) {
613
QString str = e.attribute("Type");
614
int n = str.find('#');
618
if(str.mid(0, n) != baseNS)
623
else if(str == "Content")
628
if(e.tagName() == "EncryptedData")
630
else if(e.tagName() == "EncryptedKey")
638
QDomElement i = findSubTag(e, "EncryptionMethod", &found);
641
QString str = i.attribute("Algorithm");
642
int n = str.find('#');
646
if(str.mid(0, n) != baseNS)
650
m = algorithmToMethod(str);
656
i = findSubTag(e, "ds:KeyInfo", &found);
665
i = findSubTag(e, "CipherData", &found);
668
i = findSubTag(i, "CipherValue", &found);
672
i = findSubTag(i, "CipherReference", &found);
675
cref.setURI(i.attribute("URI"));
676
QDomElement tf = i.firstChild().toElement();
678
cref.setTransforms(tf);
681
// encryption properties
682
EncryptionProperties props;
683
i = findSubTag(e, "EncryptionProperties", &found);
685
if(!props.fromXml(i))
691
i = findSubTag(e, "ReferenceList", &found);
693
QDomNodeList l = e.elementsByTagName("DataReference");
694
for(int n = 0; n < (int)l.count(); ++n) {
695
QDomElement dr = l.item(n).toElement();
697
r.setURI(dr.attribute("URI"));
698
QDomElement tf = i.firstChild().toElement();
707
i = findSubTag(e, "CarriedKeyName", &found);
711
// looks good, let's take it
721
v_carrykeyname = carrykey;
726
QString Encrypted::methodToAlgorithm(Method m, Type t) const
730
s = (t == Key ? "kw-tripledes": "tripledes-cbc");
731
else if(m == AES_128)
732
s = (t == Key ? "kw-aes128": "aes128-cbc");
733
else if(m == AES_256)
734
s = (t == Key ? "kw-aes256": "aes256-cbc");
735
else if(m == RSA_1_5)
737
else if(m == RSA_OAEP)
738
s = "rsa-oaep-mgf1p";
745
Method Encrypted::algorithmToMethod(const QString &s) const
748
if(s == "tripledes-cbc" || s == "kw-tripledes")
750
else if(s == "aes128-cbc" || s == "kw-aes128")
752
else if(s == "aes256-cbc" || s == "kw-aes256")
754
else if(s == "rsa-1_5")
756
else if(s == "rsa-oaep-mgf1p")