// header file for OpenSSL library

#include <openssl/crypto.h>

#include <openssl/x509.h>

#include <openssl/pkcs12.h>

#include <openssl/pkcs7.h>

#include <string.h>

// can be undefined in older versions of OpenSSL (otherwise in pkcs7.h)

#define PKCS7_NOCRL 0x2000

// reads a certificate and a private key from PKCS#12 file

// (in this case the file cannot be protected by password)

void load_pkcs12 ( BIO * in , EVP_PKEY ** pkey , X509 ** cert , STACK_OF ( X509 ) ** ca )

{

PKCS12 * p12 ;

p12 = d2i_PKCS12_bio ( in , NULL ) ;

if ( p12 == NULL ) return ;

if ( ! PKCS12_verify_mac ( p12 , "" , 0 ) && ! PKCS12_verify_mac ( p12 , NULL , 0 ) ) return ;

int ret = PKCS12_parse ( p12 , "" , pkey , cert , ca ) ;

if ( p12 ) PKCS12_free ( p12 ) ;

if ( ! ret ) return ;

}

int main ( )

{

// initialize library

CRYPTO_malloc_init ( ) ;

ERR_load_crypto_strings ( ) ;

OpenSSL_add_all_algorithms ( ) ;

ERR_load_OBJ_strings ( ) ;

// read the private key and corresponding certificate

X509 * signer = NULL ;

EVP_PKEY * key = NULL ;

BIO * pkcs12file = BIO_new_file ( "klic.p12" , "rb" ) ;

load_pkcs12 ( pkcs12file ,& key ,& signer , NULL ) ;

BIO_free ( pkcs12file ) ;

// fill in the data

struct data

{

char name [ 100 ] , surname [ 100 ] ;

unsigned char minutiae [ 512 ] ;

} record1 ;

strcpy ( record1. name , "Magda" ) ;

// sign and encrypt

BIO * in_record = BIO_new_mem_buf ( ( void * ) & record1 , sizeof ( struct data ) ) ;

BIO * out_signed = BIO_new_file ( "signed_and_encrypted_file.txt" , "wb" ) ;

PKCS7 * p7 = PKCS7_sign ( signer , key , NULL , in_record , PKCS7_BINARY ) ;

BIO * encipher = BIO_new ( BIO_f_cipher ( ) ) ;

BIO * out_encrypted = BIO_push ( encipher , out_signed ) ;

BIO_set_cipher ( out_encrypted , EVP_aes_128_cbc ( ) , ( unsigned char * ) "12345678ABCDEFGH" , ( unsigned char * ) "00000000" , 1 ) ;

i2d_PKCS7_bio ( out_encrypted , p7 ) ;

BIO_flush ( out_encrypted ) ;

BIO_free ( in_record ) ;

BIO_free_all ( out_encrypted ) ;

// decrypt and verify signature

X509_STORE * store = X509_STORE_new ( ) ;

X509_LOOKUP * lookup = X509_STORE_add_lookup ( store , X509_LOOKUP_hash_dir ( ) ) ;

X509_LOOKUP_add_dir ( lookup , "root" , X509_FILETYPE_PEM ) ;

STACK_OF ( X509 ) * othercerts = sk_X509_new_null ( ) ;

sk_X509_push ( othercerts , signer ) ;

BIO * p7_in = BIO_new_file ( "signed_and_encrypted_file.txt" , "rb" ) ;

BIO * decipher = BIO_new ( BIO_f_cipher ( ) ) ;

BIO_set_cipher ( decipher , EVP_aes_128_cbc ( ) , ( unsigned char * ) "12345678ABCDEFGH" , ( unsigned char * ) "00000000" , 0 ) ;

p7_in = BIO_push ( decipher , p7_in ) ;

BIO * data_out = BIO_new ( BIO_s_mem ( ) ) ;

PKCS7 * read_p7 = d2i_PKCS7_bio ( p7_in , NULL ) ;

if ( PKCS7_verify ( read_p7 , othercerts , store , NULL , data_out , PKCS7_NOCRL | PKCS7_BINARY ) )

printf ( "Signature verified

" ) ;

else

printf ( "Signature verification failed

" ) ;

BIO_free_all ( p7_in ) ;

struct data * record2 ;

int length = BIO_get_mem_data ( data_out , & record2 ) ;

if ( length != sizeof ( struct data ) )

printf ( "Size of data does not match

" ) ;

printf ( "The data is '%s'

" , record2 -> name ) ;

BIO_free ( data_out ) ;

return 0 ;