blautenb 2003/10/25 03:26:47
Modified: c/src/tools/checksig checksig.cpp
c/src/tools/cipher cipher.cpp
Log:
Clean up cipher
Revision Changes Path
1.26 +2 -1 xml-security/c/src/tools/checksig/checksig.cpp
Index: checksig.cpp
===================================================================
RCS file: /home/cvs/xml-security/c/src/tools/checksig/checksig.cpp,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- checksig.cpp 12 Oct 2003 06:23:40 -0000 1.25
+++ checksig.cpp 25 Oct 2003 10:26:47 -0000 1.26
@@ -324,6 +324,7 @@
}
#endif
else {
+ cerr << "Unknown option: " << argv[paramCount] << endl
<< endl;
printUsage();
return 2;
}
1.7 +433 -117 xml-security/c/src/tools/cipher/cipher.cpp
Index: cipher.cpp
===================================================================
RCS file: /home/cvs/xml-security/c/src/tools/cipher/cipher.cpp,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- cipher.cpp 19 Oct 2003 11:00:27 -0000 1.6
+++ cipher.cpp 25 Oct 2003 10:26:47 -0000 1.7
@@ -76,6 +76,8 @@
#include <xsec/enc/XSECCryptoException.hpp>
#include <xsec/enc/OpenSSL/OpenSSLCryptoSymmetricKey.hpp>
#include <xsec/utils/XSECBinTXFMInputStream.hpp>
+#include <xsec/xenc/XENCEncryptedData.hpp>
+#include <xsec/xenc/XENCEncryptedKey.hpp>
#include "MerlinFiveInteropResolver.hpp"
@@ -92,6 +94,7 @@
#include <memory.h>
#include <string.h>
#include <iostream>
+#include <fstream>
#include <stdlib.h>
#if defined(HAVE_UNISTD_H)
@@ -117,14 +120,17 @@
#include <xercesc/util/XMLUri.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/util/Janitor.hpp>
+#include <xercesc/util/BinFileInputStream.hpp>
#include <xercesc/framework/XMLFormatter.hpp>
#include <xercesc/framework/StdOutFormatTarget.hpp>
+#include <xercesc/framework/LocalFileFormatTarget.hpp>
XERCES_CPP_NAMESPACE_USE
using std::cerr;
using std::cout;
using std::endl;
+using std::ostream;
#ifndef XSEC_NO_XALAN
@@ -146,7 +152,11 @@
// OpenSSL
# include <xsec/enc/OpenSSL/OpenSSLCryptoKeyHMAC.hpp>
+# include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
# include <openssl/err.h>
+# include <openssl/bio.h>
+# include <openssl/evp.h>
+# include <openssl/pem.h>
#endif
@@ -181,12 +191,31 @@
cerr << "\nUsage: cipher [options] <input file name>\n\n";
cerr << " Where options are :\n\n";
+ cerr << " --decrypt/-d\n";
+ cerr << " Operate in decrypt mode (default) - outputs the
decrypted octet stream\n";
+ cerr << " Reads in the input file as an XML file, searches for
an EncryptedData node\n";
+ cerr << " and decrypts the content\n";
cerr << " --decrypt-element/-de\n";
- cerr << " Decrypt the first encrypted element found\n";
- cerr << " --key/-k [key string]\n";
- cerr << " Use the key provided in [key string] to
encrypt/decrypt\n";
+ cerr << " Operate in decrypt and XML mode.\n";
+ cerr << " This will output the original XML document with the
first encrypted\n";
+ cerr << " element decrypted.\n";
+ cerr << " --encrypt-file/-de\n";
+ cerr << " Encrypt the contents of the input file as raw data
and create an\n";
+ cerr << " XML Encrypted Data outpu\n";
+ cerr << " --key/-k [kek] <KEY_TYPE> [options]\n";
+ cerr << " Set the key to use.\n";
+ cerr << " If the first parameter is \"kek\", the key
arguments will be used\n";
+ cerr << " as a Key EncryptionKey\n";
+ cerr << " KEY_TYPE defines what the key is. Can be one of
:\n";
+ cerr << " X509, RSA, AES128, AES192, AES256 or 3DES\n";
+ cerr << " options are :\n";
+ cerr << " <filename> - for X509 PEM files (must be an
RSA KEK certificate\n";
+ cerr << " <filename> <password> - for RSA private key
files (MUST be a KEK)\n";
+ cerr << " <key-string> - For a string to use as the
key for AES or DES keys\n";
cerr << " --interop/-i\n";
cerr << " Use the interop resolver for Baltimore interop
examples\n";
+ cerr << " --out-file/-o\n";
+ cerr << " Output the result to the indicated file (rather than
stdout)\n";
#if defined (HAVE_OPENSSL) && defined (HAVE_WINCAPI)
cerr << " --wincapi/-w\n";
cerr << " Use Windows Crypto API rather than OpenSSL\n";
@@ -202,10 +231,23 @@
int evaluate(int argc, char ** argv) {
char * filename = NULL;
- char * keyStr = NULL;
+ char * outfile = NULL;
+ unsigned char * keyStr = NULL;
+ bool doDecrypt = true;
+ bool errorsOccured = false;
bool doDecryptElement = false;
bool useInteropResolver = false;
-
+ bool encryptFileAsData = false;
+ bool parseXMLInput = true;
+ bool doXMLOutput = false;
+ XSECCryptoKey * kek = NULL;
+ XSECCryptoKey * key = NULL;
+ int keyLen;
+ encryptionMethod kekAlg;
+ encryptionMethod keyAlg;
+ DOMDocument *doc;
+ unsigned char keyBuf[24];
+ XMLFormatTarget *formatTarget ;
#if defined(_WIN32) && defined (HAVE_WINCAPI)
HCRYPTPROV win32DSSCSP = 0;
// Crypto Providers
@@ -229,13 +271,34 @@
if (stricmp(argv[paramCount], "--decrypt-element") == 0 ||
stricmp(argv[paramCount], "-de") == 0) {
paramCount++;
+ doDecrypt = true;
doDecryptElement = true;
+ doXMLOutput = true;
+ parseXMLInput = true;
}
else if (stricmp(argv[paramCount], "--interop") == 0 ||
stricmp(argv[paramCount], "-i") == 0) {
// Use the interop key resolver
useInteropResolver = true;
paramCount++;
}
+ else if (stricmp(argv[paramCount], "--encrypt-file") == 0) {
+ // Use this file as the input
+ doDecrypt = false;
+ encryptFileAsData = true;
+ doXMLOutput = true;
+ parseXMLInput = false;
+ paramCount++;
+ }
+ else if (stricmp(argv[paramCount], "--out-file") == 0 ||
stricmp(argv[paramCount], "-o") == 0) {
+ if (paramCount +2 >= argc) {
+ printUsage();
+ return 1;
+ }
+ paramCount++;
+ outfile = argv[paramCount];
+ paramCount++;
+ }
+
#if defined (HAVE_WINCAPI) && defined (HAVE_OPENSSL)
else if (stricmp(argv[paramCount], "--wincapi") == 0 ||
stricmp(argv[paramCount], "-w") == 0) {
// Use the interop key resolver
@@ -246,12 +309,218 @@
#endif
else if (stricmp(argv[paramCount], "--key") == 0 ||
stricmp(argv[paramCount], "-k") == 0) {
- // Have set a key string
- paramCount++;
- keyStr = argv[paramCount];
+ // Have a key!
paramCount++;
+ bool isKEK = false;
+ XSECCryptoSymmetricKey::SymmetricKeyType loadKeyAs;
+
+ if (stricmp(argv[paramCount], "kek") == 0) {
+ isKEK = true;
+ paramCount++;
+ if (paramCount >= argc) {
+ printUsage();
+ return 2;
+ }
+ }
+
+ if (stricmp(argv[paramCount], "3DES") == 0 ||
+ stricmp(argv[paramCount], "AES128") == 0 ||
+ stricmp(argv[paramCount], "AES192") == 0 ||
+ stricmp(argv[paramCount], "AES256") == 0 ) {
+
+ if (paramCount +2 >= argc) {
+ printUsage();
+ return 2;
+ }
+
+ switch(argv[paramCount][4]) {
+ case '\0' :
+ keyLen = 24;
+ loadKeyAs =
XSECCryptoSymmetricKey::KEY_3DES_CBC_192;
+ keyAlg = ENCRYPT_3DES_CBC;
+ break;
+ case '2' :
+ keyLen = 16;
+ if (isKEK) {
+ loadKeyAs =
XSECCryptoSymmetricKey::KEY_AES_ECB_128;
+ kekAlg = ENCRYPT_KW_AES128;
+ }
+ else {
+ loadKeyAs =
XSECCryptoSymmetricKey::KEY_AES_CBC_128;
+ keyAlg = ENCRYPT_AES128_CBC;
+ }
+ break;
+ case '9' :
+ keyLen = 24;
+ if (isKEK) {
+ loadKeyAs =
XSECCryptoSymmetricKey::KEY_AES_ECB_192;
+ kekAlg = ENCRYPT_KW_AES192;
+ }
+ else {
+ loadKeyAs =
XSECCryptoSymmetricKey::KEY_AES_CBC_192;
+ keyAlg = ENCRYPT_AES192_CBC;
+ }
+ break;
+ case '5' :
+ keyLen = 32;
+ if (isKEK) {
+ loadKeyAs =
XSECCryptoSymmetricKey::KEY_AES_ECB_256;
+ kekAlg = ENCRYPT_KW_AES256;
+ }
+ else {
+ loadKeyAs =
XSECCryptoSymmetricKey::KEY_AES_CBC_256;
+ keyAlg = ENCRYPT_AES256_CBC;
+ }
+ break;
+ }
+
+ paramCount++;
+ keyStr = (unsigned char *) argv[paramCount];
+ paramCount++;
+ XSECCryptoSymmetricKey * sk =
+
XSECPlatformUtils::g_cryptoProvider->keySymmetric(loadKeyAs);
+ sk->setKey((unsigned char *) keyStr, keyLen);
+ if (isKEK)
+ kek = sk;
+ else
+ key = sk;
+ }
+
+
+
+#if defined (HAVE_OPENSSL)
+
+ else if (stricmp(argv[paramCount], "RSA") == 0) {
+ // RSA private key file
+
+ if (paramCount + 3 >= argc) {
+
+ printUsage();
+ return 2;
+
+ }
+
+ if (!isKEK) {
+ cerr << "RSA private keys may only be
KEKs\n";
+ return 2;
+ }
+
+ BIO * bioKey;
+ if ((bioKey = BIO_new(BIO_s_file())) == NULL) {
+
+ cerr << "Error opening private key
file\n\n";
+ return 1;
+
+ }
+
+ if (BIO_read_filename(bioKey, argv[paramCount +
1]) <= 0) {
+
+ cerr << "Error opening private key
file\n\n";
+ return 1;
+
+ }
+
+ EVP_PKEY * pkey;
+ pkey =
PEM_read_bio_PrivateKey(bioKey,NULL,NULL,argv[paramCount + 2]);
+
+ if (pkey == NULL) {
+
+ cerr << "Error loading private key\n\n";
+ return 1;
+
+ }
+
+ kek = new OpenSSLCryptoKeyRSA(pkey);
+ kekAlg = ENCRYPT_RSA_15;
+ EVP_PKEY_free(pkey);
+ BIO_free(bioKey);
+ paramCount += 3;
+ }
+
+ else if (stricmp(argv[paramCount], "X509") == 0) {
+
+ // X509 cert used to load an encrypting key
+
+ if (paramCount + 2 >= argc) {
+
+ printUsage();
+ exit (1);
+
+ }
+
+ if (!isKEK) {
+ cerr << "X509 private keys may only be
KEKs\n";
+ return 2;
+ }
+
+ // Load the encrypting key
+ // For now just read a particular file
+
+ BIO * bioX509;
+
+ if ((bioX509 = BIO_new(BIO_s_file())) == NULL) {
+
+ cerr << "Error opening file\n\n";
+ exit (1);
+
+ }
+
+ if (BIO_read_filename(bioX509, argv[paramCount
+ 1]) <= 0) {
+
+ cerr << "Error opening X509 Certificate
" << argv[paramCount + 1] << "\n\n";
+ exit (1);
+
+ }
+
+ X509 * x
+ ;
+ x =
PEM_read_bio_X509_AUX(bioX509,NULL,NULL,NULL);
+
+ if (x == NULL) {
+
+ BIO * bio_err;
+
+ if ((bio_err=BIO_new(BIO_s_file())) !=
NULL)
+
BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
+
+ cerr << "Error loading certificate
key\n\n";
+ ERR_print_errors(bio_err);
+ BIO_free(bio_err);
+ exit (1);
+
+ }
+
+ // Now load the key
+ EVP_PKEY *pkey;
+
+ pkey = X509_get_pubkey(x);
+
+ if (pkey == NULL || pkey->type != EVP_PKEY_RSA)
{
+ cerr << "Error extracting RSA key from
certificate" << endl;
+ }
+
+ kek = new OpenSSLCryptoKeyRSA(pkey);
+ kekAlg = ENCRYPT_RSA_15;
+
+ // Clean up
+
+ EVP_PKEY_free (pkey);
+ X509_free(x);
+ BIO_free(bioX509);
+
+ paramCount += 2;
+
+ } /* argv[1] = "--x509cert" */
+ else {
+ printUsage();
+ return 2;
+ }
}
+
+#endif /* HAVE_OPENSSL */.
+
else {
+ cerr << "Unknown option: " << argv[paramCount] << endl;
printUsage();
return 2;
}
@@ -262,129 +531,190 @@
return 2;
}
+ if (outfile != NULL) {
+ formatTarget = new LocalFileFormatTarget(outfile);
+ }
+ else {
+ formatTarget = new StdOutFormatTarget();
+ }
+
filename = argv[paramCount];
- // Create and set up the parser
+ if (parseXMLInput) {
- XercesDOMParser * parser = new XercesDOMParser;
- Janitor<XercesDOMParser> j_parser(parser);
+ XercesDOMParser * parser = new XercesDOMParser;
+ Janitor<XercesDOMParser> j_parser(parser);
+
+ parser->setDoNamespaces(true);
+ parser->setCreateEntityReferenceNodes(true);
+
+ // Now parse out file
+
+ int errorCount = 0;
+ try
+ {
+ parser->parse(filename);
+ errorCount = parser->getErrorCount();
+ if (errorCount > 0)
+ errorsOccured = true;
+ }
- parser->setDoNamespaces(true);
- parser->setCreateEntityReferenceNodes(true);
+ catch (const XMLException& e)
+ {
+ cerr << "An error occured during parsing\n Message: "
+ << e.getMessage() << endl;
+ errorsOccured = true;
+ }
- // Now parse out file
-
- bool errorsOccured = false;
- int errorCount = 0;
- try
- {
- parser->parse(filename);
- errorCount = parser->getErrorCount();
- if (errorCount > 0)
- errorsOccured = true;
- }
-
- catch (const XMLException& e)
- {
- cerr << "An error occured during parsing\n Message: "
- << e.getMessage() << endl;
- errorsOccured = true;
- }
-
-
- catch (const DOMException& e)
- {
- cerr << "A DOM error occured during parsing\n DOMException code: "
- << e.code << endl;
- errorsOccured = true;
- }
- if (errorsOccured) {
+ catch (const DOMException& e)
+ {
+ cerr << "A DOM error occured during parsing\n DOMException
code: "
+ << e.code << endl;
+ errorsOccured = true;
+ }
- cout << "Errors during parse" << endl;
- return (2);
+ if (errorsOccured) {
- }
+ cout << "Errors during parse" << endl;
+ return (2);
- /*
+ }
- Now that we have the parsed file, get the DOM document and
start looking at it
+ /*
- */
-
- DOMNode *doc; // The document that we parsed
+ Now that we have the parsed file, get the DOM document
and start looking at it
- doc = parser->getDocument();
- DOMDocument *theDOM = parser->getDocument();
+ */
+
+ doc = parser->adoptDocument();
+ }
+
+ else {
+ // Create an empty document
+ XMLCh tempStr[100];
+ XMLString::transcode("Core", tempStr, 99);
+ DOMImplementation *impl =
DOMImplementationRegistry::getDOMImplementation(tempStr);
+ doc = impl->createDocument(
+ 0, // root element namespace URI.
+ MAKE_UNICODE_STRING("ADoc"), // root element
name
+ NULL);// DOMDocumentType()); // document type object
(DTD).
+ }
- XSECProvider prov;
- // Find the EncryptedData node
- DOMNode * n = findXENCNode(doc, "EncryptedData");
+ XSECProvider prov;
+ XENCCipher * cipher = prov.newCipher(doc);
- XENCCipher * cipher = prov.newCipher(theDOM);
+ if (kek != NULL)
+ cipher->setKEK(kek);
+ if (key != NULL)
+ cipher->setKey(key);
try {
-#if defined (HAVE_OPENSSL)
- OpenSSLCryptoSymmetricKey * k;
- if (keyStr != NULL) {
- k = new
OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_3DES_CBC_192);
- k->setKey((unsigned char *) keyStr, strlen(keyStr));
- cipher->setKey(k);
- }
-#else
- WinCAPICryptoSymmetricKey * k;
- if (keyStr != NULL) {
- k = new WinCAPICryptoSymmetricKey(win32RSACSP,
XSECCryptoSymmetricKey::KEY_3DES_CBC_192);
- k->setKey((unsigned char *) keyStr, strlen(keyStr));
- cipher->setKey(k);
- }
-#endif
+ if (doDecrypt) {
+
+ if (useInteropResolver == true) {
- if (useInteropResolver == true) {
+ // Map out base path of the file
+ char path[_MAX_PATH];
+ char baseURI[(_MAX_PATH * 2) + 10];
+ getcwd(path, _MAX_PATH);
+
+ strcpy(baseURI, "file:///");
+
+ // Ugly and nasty but quick
+ if (filename[0] != '\\' && filename[0] != '/'
&& filename[1] != ':') {
+ strcat(baseURI, path);
+ strcat(baseURI, "/");
+ } else if (path[1] == ':') {
+ path[2] = '\0';
+ strcat(baseURI, path);
+ }
- // Map out base path of the file
- char path[_MAX_PATH];
- char baseURI[(_MAX_PATH * 2) + 10];
- getcwd(path, _MAX_PATH);
+ strcat(baseURI, filename);
- strcpy(baseURI, "file:///");
+ // Find any ':' and "\" characters
+ int lastSlash = 0;
+ for (unsigned int i = 8; i < strlen(baseURI);
++i) {
+ if (baseURI[i] == '\\') {
+ lastSlash = i;
+ baseURI[i] = '/';
+ }
+ else if (baseURI[i] == '/')
+ lastSlash = i;
+ }
+
+ // The last "\\" must prefix the filename
+ baseURI[lastSlash + 1] = '\0';
+
+ XMLUri uri(MAKE_UNICODE_STRING(baseURI));
+
+ MerlinFiveInteropResolver
ires(&(uri.getUriText()[8]));
+ cipher->setKeyInfoResolver(&ires);
- // Ugly and nasty but quick
- if (filename[0] != '\\' && filename[0] != '/' &&
filename[1] != ':') {
- strcat(baseURI, path);
- strcat(baseURI, "/");
- } else if (path[1] == ':') {
- path[2] = '\0';
- strcat(baseURI, path);
}
+ // Find the EncryptedData node
+ DOMNode * n = findXENCNode(doc, "EncryptedData");
- strcat(baseURI, filename);
+ if (doDecryptElement) {
+ // Find the EncryptedData node
+ cipher->decryptElement(static_cast<DOMElement
*>(n));
- // Find any ':' and "\" characters
- int lastSlash = 0;
- for (unsigned int i = 8; i < strlen(baseURI); ++i) {
- if (baseURI[i] == '\\') {
- lastSlash = i;
- baseURI[i] = '/';
+ }
+ else {
+ XSECBinTXFMInputStream * bis =
cipher->decryptToBinInputStream(static_cast<DOMElement *>(n));
+
+ XMLByte buf[1024];
+ unsigned int read = bis->readBytes(buf, 1023);
+ while (read > 0) {
+ formatTarget->writeChars(buf, read,
NULL);
+ read = bis->readBytes(buf, 1023);
}
- else if (baseURI[i] == '/')
- lastSlash = i;
+ delete bis;
}
+ }
+ else {
- // The last "\\" must prefix the filename
- baseURI[lastSlash + 1] = '\0';
+ XENCEncryptedData *xenc;
- XMLUri uri(MAKE_UNICODE_STRING(baseURI));
+ // Encrypting
+ if (kek != NULL && key == NULL) {
+
XSECPlatformUtils::g_cryptoProvider->getRandom(keyBuf, 24);
+ XSECCryptoSymmetricKey * k =
+
XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_3DES_CBC_192);
+ k->setKey(keyBuf, 24);
+ cipher->setKey(k);
+ keyAlg = ENCRYPT_3DES_CBC;
+ keyStr = keyBuf;
+ keyLen = 24;
+ }
+
+ if (encryptFileAsData) {
- MerlinFiveInteropResolver ires(&(uri.getUriText()[8]));
- cipher->setKeyInfoResolver(&ires);
+ // Create a BinInputStream
+ BinFileInputStream * is = new
BinFileInputStream(filename, XMLPlatformUtils::fgMemoryManager);
+ xenc = cipher->encryptBinInputStream(is,
keyAlg);
+
+ // Replace the document element
+ DOMElement * elt = doc->getDocumentElement();
+ doc->replaceChild(xenc->getDOMNode(), elt);
+ elt->release();
+ }
+ else {
+ cerr << "Element encryption not yet supported"
<< endl;
+ return (2);
+ }
+ // Do we encrypt a created key?
+ if (kek != NULL) {
+ XENCEncryptedKey *xkey =
cipher->encryptKey(keyStr, keyLen, kekAlg);
+ // Add to the EncryptedData
+ xenc->appendEncryptedKey(xkey);
+ }
}
- if (doDecryptElement) {
- cipher->decryptElement(static_cast<DOMElement *>(n));
+ if (doXMLOutput) {
// Output the result
XMLCh core[] = {
@@ -402,29 +732,11 @@
if
(theSerializer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, false))
theSerializer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, false);
-
- XMLFormatTarget *formatTarget = new
StdOutFormatTarget();
-
theSerializer->writeNode(formatTarget, *doc);
cout << endl;
delete theSerializer;
- delete formatTarget;
-
- }
-
- else {
-
- XSECBinTXFMInputStream * bis =
cipher->decryptToBinInputStream(static_cast<DOMElement *>(n));
- XMLByte buf[1024];
- unsigned int read = bis->readBytes(buf, 1023);
- while (read > 0) {
- buf[read] = '\0';
- cout << buf;
- read = bis->readBytes(buf, 1023);
- }
- delete bis;
}
}
@@ -451,7 +763,11 @@
#endif
return 2;
}
+
+ if (formatTarget != NULL)
+ delete formatTarget;
+ doc->release();
return 0;
}