|  | Home | Documentation | The mecevp streaming message encryption and decryption engine updated by Robert van Engelen |

The mecevp streaming message encryption and decryption engine

The gSOAP mecevp engine encrypts and decrypts messages using the EVP interface of OpenSSL. It supports envelope encryption/decryption with public and private RSA keys and symmetric encryption with shared secret keys. Streaming and buffered message encryption modes are supported.

An encryption and decryption algorithm and mode is selected with one of the following:

- SOAP_MEC_ENV_ENC_DES_CBC envelope encryption with triple DES EDE CBC
- SOAP_MEC_ENV_ENC_AES256_CBC envelope encryption with AES256 CBC
- SOAP_MEC_ENV_ENC_AES256_GCM envelope authenticated encryption with AES256 GCM
- SOAP_MEC_ENC_DES_CBC symmetric encryption with triple DES EDE CBC
- SOAP_MEC_ENC_AES256_CBC symmetric encryption with AES256 CBC
- SOAP_MEC_ENC_AES256_GCM symmetric authenticated encryption with AES256 GCM
- SOAP_MEC_ENV_DEC_DES_CBC envelope decryption with triple DES EDE CBC
- SOAP_MEC_ENV_DEC_AES256_CBC envelope decryption with AES256 CBC
- SOAP_MEC_ENV_DEC_AES256_GCM envelope authenticated decryption with AES256 GCM
- SOAP_MEC_DEC_DES_CBC symmetric decryption with triple DES EDE CBC
- SOAP_MEC_DEC_AES256_CBC symmetric decryption with AES256 CBC
- SOAP_MEC_DEC_AES256_GCM symmetric authenticated decryption with AES256 GCM

where, in the above, AES256 can be replaced with AES128 ot AES192.

Algorithm options:

- SOAP_MEC_STORE buffer all output in memory
- SOAP_MEC_OAEP use OAEP padding for CBC

The mecevp engine wraps the EVP API with four new functions:

- soap_mec_init to initialize the engine
- soap_mec_update to encrypt/decrypt a message part
- soap_mec_final to finalize encryption/decryption, does not deallocate tne engine and buffers
- soap_mec_cleanup to deallocate the engine and buffers

All cipher data is written and read in base64 format.

A higher-level interface for message encryption/decryption in parts (such as individual XML elements) is defined by two new functions:

- soap_mec_begin to begin a streaming sequence of encryptions/decryptions
- soap_mec_start to start encryption/decryption of a message part
- soap_mec_stop to stop encryption/decryption of a message part
- soap_mec_end to end the sequence and deallocate the engine buffers

Compile all source codes with -DWITH_OPENSSL and link with ssl and crypto libraries.

Here is an example to encrypt a message while streaming it to the output. The example uses the public key of the recipient/reader of the message. The recipient/reader uses its private key to decrypt. Envelope encryption is used with SOAP_MEC_ENV_ENC_DES_CBC, which means an ephemeral secret key is generated and encrypted with the public key. This encrypted secret key should be communicated to the recipient/reader with the message to decrypt:

#include "mecevp.h"
soap_mec_data mec;
ns__Object object;
int alg = SOAP_MEC_ENV_ENC_DES_CBC;
FILE *fd = fopen("key.pem", "r");
EVP_PKEY *pubk;
unsigned char *key;
int keylen;
if (...) // key file contains public key?
pubk = PEM_read_PUBKEY(fd, NULL, NULL, NULL);
else // key file contains certificate
{
X509 *cert = PEM_read_X509(fd, NULL, NULL, NULL);
pubk = X509_get_pubkey(cert);
X509_free(cert);
}
fclose(fd);
key = soap_malloc(soap, soap_mec_size(alg, pubk));
if (soap_begin_send(soap)
|| soap_mec_begin(soap, &mec, alg, pubk, key, &keylen)
|| soap_mec_start(soap, NULL)
|| soap_out_ns__Object(soap, "ns:Object", 0, &object, NULL)
|| soap_mec_stop(soap)
|| soap_mec_end(soap, &mec)
|| soap_end_send(soap))
{
soap_mec_cleanup(soap, &mec); // clean up when error
soap_print_fault(soap, stderr);
}
EVP_PKEY_free(pubk);
mecevp.h
soap_mec_begin
SOAP_FMAC1 int SOAP_FMAC2 soap_mec_begin(struct soap *soap, struct soap_mec_data *data, int alg, SOAP_MEC_KEY_TYPE *pkey, unsigned char *key, int *keylen)
Initialize the mecevp engine data and begin encryption or decryption message sequence using a private...
Definition mecevp.c:558
soap_mec_end
SOAP_FMAC1 int SOAP_FMAC2 soap_mec_end(struct soap *soap, struct soap_mec_data *data)
Ends encryption or decryption of a sequence of message parts that began with soap_mec_begin.
Definition mecevp.c:787
soap_mec_cleanup
SOAP_FMAC1 void SOAP_FMAC2 soap_mec_cleanup(struct soap *soap, struct soap_mec_data *data)
Clean up mecevp engine and deallocate cipher context and buffers.
Definition mecevp.c:512
SOAP_MEC_ENV_ENC_DES_CBC
#define SOAP_MEC_ENV_ENC_DES_CBC
Definition mecevp.h:158
soap_mec_size
SOAP_FMAC1 size_t SOAP_FMAC2 soap_mec_size(int alg, SOAP_MEC_KEY_TYPE *pkey)
Returns the number of octets needed to store the public/private key or the symmetric key,...
Definition mecevp.c:816
soap_mec_stop
SOAP_FMAC1 int SOAP_FMAC2 soap_mec_stop(struct soap *soap)
Stops encryption or decryption of current message. Use after soap_mec_start.
Definition mecevp.c:750
soap_mec_start
SOAP_FMAC1 int SOAP_FMAC2 soap_mec_start(struct soap *soap, const unsigned char *key)
Start encryption or decryption of current message. If key is non-NULL, use the symmetric key with alg...
Definition mecevp.c:734
soap_mec_data
The mecevp engine context data.
Definition mecevp.h:193

The example given above sends the output to stdout. To save the output in a string use the following in C:

char *str = NULL; // string to be set to the encrypted output
soap->os = &str; // for C code only
if (soap_begin_send(soap)
...
soap->os = NULL;
... // use str, which is set to the encrypted output
soap_end(soap); // auto-deletes str

With C++ you should use a string stream:

std::stringstream ss;
soap->os = &ss;
if (soap_begin_send(soap)
...
soap->os = NULL;
... // use ss.str()
soap_destroy(soap); // cleanup
soap_end(soap); // cleanup

The decryption by the recipient/reader requires the ephemeral encrypted secret key generated by soap_mec_begin by the sender (as set above) to decrypt the message using envelope decryption with SOAP_MEC_ENV_DEC_DES_CBC.

#include "mecevp.h"
soap_mec_data mec;
ns__Object object;
int alg = SOAP_MEC_ENV_DEC_DES_CBC;
FILE *fd = fopen("key.pem", "r");
EVP_PKEY *privk = PEM_read_PrivateKey(fd, NULL, NULL, "password");
unsigned char *key;
int keylen;
fclose(fd);
key = ... // value set as above by sender
keylen = ... // value set as above by sender
if (soap_begin_recv(soap)
|| soap_mec_begin(soap, &mec, alg, privk, key, &keylen)
|| soap_mec_start(soap)
|| soap_in_ns__Object(soap, "ns:Object", &object, NULL) == NULL
|| soap_mec_stop(soap)
|| soap_mec_end(soap, &mec)
|| soap_end_recv(soap))
{
soap_mec_cleanup(soap, &mec); // clean up when error
soap_print_fault(soap, stderr);
}
EVP_PKEY_free(privk);
SOAP_MEC_ENV_DEC_DES_CBC
#define SOAP_MEC_ENV_DEC_DES_CBC
Definition mecevp.h:169

The example given above reads the input from stdin. To read input from a string use the following in C:

char *str; // string with encrupted input
soap->is = str;
if (soap_begin_recv(soap)
...
soap->is = NULL;
soap_end(soap); // cleanup

With C++ you should use a string stream:

std::stringstream ss;
ss.str(...); // string with encrypted input
soap->is = &ss;
if (soap_begin_recv(soap)
...
soap->is = NULL;
soap_destroy(soap); // cleanup
soap_end(soap); // cleanup

Note that the encrypted secret key can be sent in the clear or stored openly, since only the recipient/reader will be able to decode it (with its private key) and use it for message decryption.

Symmetric encryption and decryption can be used if both parties can safely share a secret symmetric key that no other party has access to. We use SOAP_MEC_ENC_DES_CBC for encryption and SOAP_MEC_DEC_DES_CBC for decryption using a 160-bit triple DES key. You can also use AES128, AES192, AES256 ciphers.

Here is an example to encrypt a message using a shared secret key while streaming it to the output.

#include "mecevp.h"
soap_mec_data mec;
ns__Object object;
int alg = SOAP_MEC_ENC_DES_CBC;
unsigned char key[20] = { ... }; // shared secret triple DES key
int keylen = 20;
if (soap_begin_send(soap)
|| soap_mec_begin(soap, &mec, alg, NULL, key, &keylen)
|| soap_mec_start(soap, NULL)
|| soap_out_ns__Object(soap, "ns:Object", 0, &object, NULL)
|| soap_mec_stop(soap)
|| soap_mec_end(soap, &mec)
|| soap_end_send(soap))
{
soap_mec_cleanup(soap, &mec); // clean up when error
soap_print_fault(soap, stderr);
}
SOAP_MEC_ENC_DES_CBC
#define SOAP_MEC_ENC_DES_CBC
Definition mecevp.h:134

The decryption by the recipient/reader requires the same shared secret key to decrypt the message using envelope decryption with SOAP_MEC_DEC_DES_CBC. This key is secret and unencrypted, so it should never be shared with any other party besides the sender/writer and recipient/reader.

#include "mecevp.h"
soap_mec_data mec;
ns__Object object;
int alg = SOAP_MEC_DEC_DES_CBC;
unsigned char key[20] = { ... }; // shared secret triple DES key
int keylen = 20;
if (soap_begin_recv(soap)
|| soap_mec_begin(soap, &mec, alg, NULL, key, &keylen)
|| soap_mec_start(soap)
|| soap_in_ns__Object(soap, "ns:Object", &object, NULL) == NULL
|| soap_mec_stop(soap)
|| soap_mec_end(soap, &mec)
|| soap_end_recv(soap))
{
soap_mec_cleanup(soap, &mec); // clean up when error
soap_print_fault(soap, stderr);
}
SOAP_MEC_DEC_DES_CBC
#define SOAP_MEC_DEC_DES_CBC
Definition mecevp.h:145

Note
  The mecevp engine uses callbacks of the gSOAP engine that were introduced in version 2.8.1. Earlier gSOAP version releases are not compatible with the mecevp plugin and engine.