#include "xmlsecrb.h"
static xmlSecKeysMngrPtr getKeyManager(char* keyStr, unsigned int keyLength, char *keyName) {
xmlSecKeysMngrPtr mngr;
xmlSecKeyPtr key;
/* create and initialize keys manager, we use a simple list based
* keys manager, implement your own xmlSecKeysStore klass if you need
* something more sophisticated
*/
mngr = xmlSecKeysMngrCreate();
if(mngr == NULL) {
rb_raise(rb_eDecryptionError, "failed to create keys manager.");
return(NULL);
}
if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) {
rb_raise(rb_eDecryptionError, "failed to initialize keys manager.");
xmlSecKeysMngrDestroy(mngr);
return(NULL);
}
/* load private RSA key */
// key = xmlSecCryptoAppKeyLoad(key_file, xmlSecKeyDataFormatPem, NULL, NULL, NULL);
key = xmlSecCryptoAppKeyLoadMemory((xmlSecByte *)keyStr,
keyLength,
xmlSecKeyDataFormatPem,
NULL, // password
NULL, NULL);
if(key == NULL) {
rb_raise(rb_eDecryptionError, "failed to load rsa key");
xmlSecKeysMngrDestroy(mngr);
return(NULL);
}
/* set key name to the file name, this is just an example! */
if(xmlSecKeySetName(key, BAD_CAST keyName) < 0) {
rb_raise(rb_eDecryptionError, "failed to set key name");
xmlSecKeyDestroy(key);
xmlSecKeysMngrDestroy(mngr);
return(NULL);
}
/* add key to keys manager, from now on keys manager is responsible
* for destroying key
*/
if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(mngr, key) < 0) {
rb_raise(rb_eDecryptionError, "failed to add key to keys manager");
xmlSecKeyDestroy(key);
xmlSecKeysMngrDestroy(mngr);
return(NULL);
}
return(mngr);
}
VALUE encrypt_with_key(VALUE self, VALUE rb_key_name, VALUE rb_key) {
xmlDocPtr doc;
xmlNodePtr encDataNode = NULL;
xmlNodePtr encKeyNode = NULL;
xmlNodePtr keyInfoNode = NULL;
xmlSecEncCtxPtr encCtx = NULL;
xmlSecKeysMngrPtr keyManager = NULL;
char *keyName;
char *key;
unsigned int keyLength;
Check_Type(rb_key_name, T_STRING);
Check_Type(rb_key, T_STRING);
Data_Get_Struct(self, xmlDoc, doc);
key = RSTRING_PTR(rb_key);
keyLength = RSTRING_LEN(rb_key);
keyName = RSTRING_PTR(rb_key_name);
// create encryption template to encrypt XML file and replace
// its content with encryption result
encDataNode = xmlSecTmplEncDataCreate(doc, xmlSecTransformDes3CbcId,
NULL, xmlSecTypeEncElement, NULL, NULL);
if(encDataNode == NULL) {
rb_raise(rb_eEncryptionError, "failed to create encryption template");
goto done;
}
// we want to put encrypted data in the node
if(xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL) {
rb_raise(rb_eEncryptionError, "failed to add CipherValue node");
goto done;
}
// add and nodes to put key name in the
// signed document
keyInfoNode = xmlSecTmplEncDataEnsureKeyInfo(encDataNode, NULL);
if(keyInfoNode == NULL) {
rb_raise(rb_eEncryptionError, "failed to add key info");
goto done;
}
if(xmlSecTmplKeyInfoAddKeyName(keyInfoNode, NULL) == NULL) {
rb_raise(rb_eEncryptionError, "failed to add key name");
goto done;
}
keyManager = getKeyManager(key, keyLength, keyName);
if (keyManager == NULL) {
rb_raise(rb_eEncryptionError, "failed to create key manager");
goto done;
}
// create encryption context, we don't need keys manager in this example
encCtx = xmlSecEncCtxCreate(keyManager);
if(encCtx == NULL) {
rb_raise(rb_eEncryptionError, "failed to create encryption context");
goto done;
}
// generate a 3DES key
// TODO make a note of this one, it lets us pass in key type and bits from ruby
encCtx->encKey = xmlSecKeyGenerateByName((xmlChar *)"des", 192,
xmlSecKeyDataTypeSession);
// encCtx->encKey = xmlSecKeyGenerate(xmlSecKeyDataDesId, 192,
// xmlSecKeyDataTypeSession);
// encCtx->encKey = xmlSecAppCryptoKeyGenerate(xmlSecAppCmdLineParamGetString(&sessionKeyParam),
// NULL, xmlSecKeyDataTypeSession);
if(encCtx->encKey == NULL) {
rb_raise(rb_eDecryptionError, "failed to generate session des key");
goto done;
}
// set key name
if(xmlSecKeySetName(encCtx->encKey, (xmlSecByte *)keyName) < 0) {
rb_raise(rb_eEncryptionError, "failed to set key name to '%s'", keyName);
goto done;
}
// add node to the tag to include
// the session key
encKeyNode = xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode,
xmlSecTransformRsaPkcs1Id, // encMethodId encryptionMethod
NULL, // xmlChar *idAttribute
NULL, // xmlChar *typeAttribute
NULL // xmlChar *recipient
);
if (encKeyNode == NULL) {
rb_raise(rb_eEncryptionError, "failed to add encrypted key node");
goto done;
}
if (xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == NULL) {
rb_raise(rb_eEncryptionError, "failed to add encrypted cipher value");
goto done;
}
// encrypt the data
if(xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, xmlDocGetRootElement(doc)) < 0) {
rb_raise(rb_eEncryptionError, "encryption failed");
goto done;
}
// the template is inserted in the doc, so don't free it
encDataNode = NULL;
encKeyNode = NULL;
done:
/* cleanup */
if(encCtx != NULL) {
xmlSecEncCtxDestroy(encCtx);
}
if (encKeyNode != NULL) {
xmlFreeNode(encKeyNode);
}
if(encDataNode != NULL) {
xmlFreeNode(encDataNode);
}
if (keyManager != NULL) {
xmlSecKeysMngrDestroy(keyManager);
}
return T_NIL;
}