in xsec/tools/cipher/cipher.cpp [206:829]
int evaluate(int argc, char ** argv) {
char * filename = 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;
#ifdef XSEC_XKMS_ENABLED
bool isXKMSKey = false;
#endif
XSECCryptoKey * kek = NULL;
XSECCryptoKey * key = NULL;
int keyLen = 0;
const XMLCh* kekAlg = NULL;
const XMLCh* keyAlg = NULL;
DOMDocument *doc;
unsigned char keyBuf[24];
XMLFormatTarget *formatTarget ;
#if defined(_WIN32) && defined (XSEC_HAVE_WINCAPI)
HCRYPTPROV win32DSSCSP = 0; // Crypto Providers
HCRYPTPROV win32RSACSP = 0;
CryptAcquireContext(&win32DSSCSP, NULL, NULL, PROV_DSS, CRYPT_VERIFYCONTEXT);
CryptAcquireContext(&win32RSACSP, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
#endif
if (argc < 2) {
printUsage();
return 2;
}
// Run through parameters
int paramCount = 1;
while (paramCount < argc - 1) {
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 || _stricmp(argv[paramCount], "-ef") == 0) {
// Use this file as the input
doDecrypt = false;
encryptFileAsData = true;
doXMLOutput = true;
parseXMLInput = false;
paramCount++;
}
else if (_stricmp(argv[paramCount], "--encrypt-xml") == 0 || _stricmp(argv[paramCount], "-ex") == 0) {
// Us this file as an XML input file
doDecrypt = false;
encryptFileAsData = false;
doXMLOutput = true;
parseXMLInput = true;
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++;
}
#ifdef XSEC_XKMS_ENABLED
else if (_stricmp(argv[paramCount], "--xkms") == 0 || _stricmp(argv[paramCount], "-x") == 0) {
paramCount++;
isXKMSKey = true;
}
#endif
#ifdef XSEC_HAVE_WINCAPI
else if (_stricmp(argv[paramCount], "--wincapi") == 0 || _stricmp(argv[paramCount], "-w") == 0) {
// Use the interop key resolver
WinCAPICryptoProvider * cp = new WinCAPICryptoProvider();
XSECPlatformUtils::SetCryptoProvider(cp);
paramCount++;
}
#endif
#ifdef XSEC_HAVE_NSS
else if (_stricmp(argv[paramCount], "--nss") == 0 || _stricmp(argv[paramCount], "-n") == 0) {
// NSS Crypto Provider
NSSCryptoProvider * cp = new NSSCryptoProvider();
XSECPlatformUtils::SetCryptoProvider(cp);
paramCount++;
}
#endif
else if (_stricmp(argv[paramCount], "--key") == 0 || _stricmp(argv[paramCount], "-k") == 0) {
// Have a key!
paramCount++;
bool isKEK = false;
XSECCryptoSymmetricKey::SymmetricKeyType loadKeyAs =
XSECCryptoSymmetricKey::KEY_NONE;
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 ||
_stricmp(argv[paramCount], "AES128-GCM") == 0 ||
_stricmp(argv[paramCount], "AES192-GCM") == 0 ||
_stricmp(argv[paramCount], "AES256-GCM") == 0) {
if (paramCount +2 >= argc) {
printUsage();
return 2;
}
switch(argv[paramCount][4]) {
case '\0' :
keyLen = 24;
loadKeyAs = XSECCryptoSymmetricKey::KEY_3DES_192;
keyAlg = DSIGConstants::s_unicodeStrURI3DES_CBC;
break;
case '2' :
keyLen = 16;
loadKeyAs = XSECCryptoSymmetricKey::KEY_AES_128;
if (isKEK) {
kekAlg = DSIGConstants::s_unicodeStrURIKW_AES128;
}
else if (strlen(argv[paramCount]) == 6) {
keyAlg = DSIGConstants::s_unicodeStrURIAES128_CBC;
}
else {
keyAlg = DSIGConstants::s_unicodeStrURIAES128_GCM;
}
break;
case '9' :
keyLen = 24;
loadKeyAs = XSECCryptoSymmetricKey::KEY_AES_192;
if (isKEK) {
kekAlg = DSIGConstants::s_unicodeStrURIKW_AES192;
}
else if (strlen(argv[paramCount]) == 6) {
keyAlg = DSIGConstants::s_unicodeStrURIAES192_CBC;
}
else {
keyAlg = DSIGConstants::s_unicodeStrURIAES192_GCM;
}
break;
case '5' :
keyLen = 32;
loadKeyAs = XSECCryptoSymmetricKey::KEY_AES_256;
if (isKEK) {
kekAlg = DSIGConstants::s_unicodeStrURIKW_AES256;
}
else if (strlen(argv[paramCount]) == 6) {
keyAlg = DSIGConstants::s_unicodeStrURIAES256_CBC;
}
else {
keyAlg = DSIGConstants::s_unicodeStrURIAES256_GCM;
}
break;
}
paramCount++;
unsigned char keyStr[64];
if (strlen(argv[paramCount]) > 64) {
cerr << "Key string too long\n";
return 2;
}
XSECCryptoSymmetricKey * sk =
XSECPlatformUtils::g_cryptoProvider->keySymmetric(loadKeyAs);
#ifdef XSEC_XKMS_ENABLED
if (isXKMSKey) {
unsigned char kbuf[XSEC_MAX_HASH_SIZE];
CalculateXKMSKEK((unsigned char *) argv[paramCount], (int) strlen(argv[paramCount]), kbuf, XSEC_MAX_HASH_SIZE);
sk->setKey(kbuf, keyLen);
}
else {
#endif
memset(keyStr, 0, 64);
strcpy((char *) keyStr, argv[paramCount]);
sk->setKey(keyStr, keyLen);
#ifdef XSEC_XKMS_ENABLED
}
#endif
paramCount++;
if (isKEK)
kek = sk;
else
key = sk;
}
#ifdef XSEC_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 = DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1;
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);
#ifdef XSEC_OPENSSL_HAVE_EVP_PKEY_ID
if (pkey == NULL || EVP_PKEY_id(pkey) != EVP_PKEY_RSA)
#else
if (pkey == NULL || pkey->type != EVP_PKEY_RSA)
#endif
{
cerr << "Error extracting RSA key from certificate" << endl;
}
kek = new OpenSSLCryptoKeyRSA(pkey);
kekAlg = DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1;
// Clean up
EVP_PKEY_free (pkey);
X509_free(x);
BIO_free(bioX509);
paramCount += 2;
} /* argv[1] = "--x509cert" */
#endif /* XSEC_HAVE_OPENSSL */
else {
printUsage();
return 2;
}
}
else {
cerr << "Unknown option: " << argv[paramCount] << endl;
printUsage();
return 2;
}
}
if (paramCount >= argc) {
printUsage();
return 2;
}
if (outfile != NULL) {
formatTarget = new LocalFileFormatTarget(outfile);
}
else {
formatTarget = new StdOutFormatTarget();
}
filename = argv[paramCount];
if (parseXMLInput) {
XercesDOMParser * parser = new XercesDOMParser;
Janitor<XercesDOMParser> j_parser(parser);
parser->setDoNamespaces(true);
parser->setCreateEntityReferenceNodes(true);
// Now parse out file
XMLSize_t errorCount = 0;
try
{
parser->parse(filename);
errorCount = parser->getErrorCount();
if (errorCount > 0)
errorsOccured = true;
}
catch (const XMLException& e)
{
cerr << "An error occurred during parsing\n Message: "
<< e.getMessage() << endl;
errorsOccured = true;
}
catch (const DOMException& e)
{
cerr << "A DOM error occurred during parsing\n DOMException code: "
<< e.code << endl;
errorsOccured = true;
}
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
*/
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;
XENCCipher * cipher = prov.newCipher(doc);
if (kek != NULL)
cipher->setKEK(kek);
if (key != NULL)
cipher->setKey(key);
try {
if (doDecrypt) {
if (useInteropResolver == true) {
// Map out base path of the file
#ifdef XSEC_HAVE_GETCWD_DYN
char *path = getcwd(NULL, 0);
char *baseURI = (char*)malloc(strlen(path) + 8 + 1 + strlen(filename) + 1);
#else
char path[PATH_MAX];
char baseURI[(PATH_MAX * 2) + 10];
getcwd(path, PATH_MAX);
#endif
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);
}
strcat(baseURI, filename);
// 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';
XMLCh * uriT = XMLString::transcode(baseURI);
#ifdef XSEC_HAVE_GETCWD_DYN
free(path);
free(baseURI);
#endif
XencInteropResolver ires(doc, &(uriT[8]));
XSEC_RELEASE_XMLCH(uriT);
cipher->setKeyInfoResolver(&ires);
}
// Find the EncryptedData node
DOMNode * n = findXENCNode(doc, "EncryptedData");
if (doDecryptElement) {
while (n != NULL) {
// decrypt
cipher->decryptElement(static_cast<DOMElement *>(n));
// Find the next EncryptedData node
n = findXENCNode(doc, "EncryptedData");
}
}
else {
XSECBinTXFMInputStream * bis = cipher->decryptToBinInputStream(static_cast<DOMElement *>(n));
Janitor<XSECBinTXFMInputStream> j_bis(bis);
XMLByte buf[1024];
XMLSize_t read = bis->readBytes(buf, 1023);
while (read > 0) {
formatTarget->writeChars(buf, read, NULL);
read = bis->readBytes(buf, 1023);
}
}
}
else {
XENCEncryptedData *xenc = NULL;
// Encrypting
if (kek != NULL && key == NULL) {
XSECPlatformUtils::g_cryptoProvider->getRandom(keyBuf, 24);
XSECCryptoSymmetricKey * k =
XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_3DES_192);
k->setKey(keyBuf, 24);
cipher->setKey(k);
keyAlg = DSIGConstants::s_unicodeStrURI3DES_CBC;
keyStr = keyBuf;
keyLen = 24;
}
if (encryptFileAsData) {
// 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->getElement(), elt);
elt->release();
}
else {
// Document encryption
cipher->encryptElement(doc->getDocumentElement(), keyAlg);
}
// Do we encrypt a created key?
if (kek != NULL && xenc != NULL) {
XENCEncryptedKey *xkey = cipher->encryptKey(keyStr, keyLen, kekAlg);
// Add to the EncryptedData
xenc->appendEncryptedKey(xkey);
}
}
if (doXMLOutput) {
// Output the result
XMLCh core[] = {
XERCES_CPP_NAMESPACE_QUALIFIER chLatin_C,
XERCES_CPP_NAMESPACE_QUALIFIER chLatin_o,
XERCES_CPP_NAMESPACE_QUALIFIER chLatin_r,
XERCES_CPP_NAMESPACE_QUALIFIER chLatin_e,
XERCES_CPP_NAMESPACE_QUALIFIER chNull
};
DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(core);
DOMLSSerializer *theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer();
Janitor<DOMLSSerializer> j_theSerializer(theSerializer);
// Get the config so we can set up pretty printing
DOMConfiguration *dc = theSerializer->getDomConfig();
dc->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, false);
// Now create an output object to format to UTF-8
DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput();
Janitor<DOMLSOutput> j_theOutput(theOutput);
theOutput->setEncoding(MAKE_UNICODE_STRING("UTF-8"));
theOutput->setByteStream(formatTarget);
theSerializer->write(doc, theOutput);
cout << endl;
}
}
catch (const XSECException &e) {
char * msg = XMLString::transcode(e.getMsg());
cerr << "An error occurred during encryption/decryption operation\n Message: "
<< msg << endl;
XSEC_RELEASE_XMLCH(msg);
errorsOccured = true;
if (formatTarget != NULL)
delete formatTarget;
doc->release();
return 2;
}
catch (const XSECCryptoException &e) {
cerr << "An error occurred during encryption/decryption operation\n Message: "
<< e.getMsg() << endl;
errorsOccured = true;
if (formatTarget != NULL)
delete formatTarget;
doc->release();
#ifdef XSEC_HAVE_OPENSSL
ERR_load_crypto_strings();
BIO * bio_err;
if ((bio_err=BIO_new(BIO_s_file())) != NULL)
BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
ERR_print_errors(bio_err);
#endif
return 2;
}
if (formatTarget != NULL)
delete formatTarget;
doc->release();
return 0;
}