How to implement Triple DES crypto in C using OpenSSL library - c

I'm trying to implement Triple DES encryption in C using OpenSSL library but I am not such professional in cryptography. I've found a useful sample code here for DES ECB crypto but I could not find an example code on how to implement 3DES and most of web resources just describe how to use OpenSSL as a tool.
I've implemented DES ECB for a specific purpose as follows
typedef struct
{
size_t size;
unsigned char* data;
} byte_array, *byte_array_ptr;
for encryption
byte_array_ptr des_encrypt_to_pin_block(byte_array_ptr key_bytes, byte_array_ptr xor_bytes)
{
if ((key_bytes->size != 8) || (xor_bytes->size != 8))
return NULL;
DES_key_schedule schedule;
const_DES_cblock key_data;
const_DES_cblock xor_data;
DES_cblock buffer;
memcpy(&key_data, key_bytes->data, key_bytes->size);
memcpy(&xor_data, xor_bytes->data, xor_bytes->size);
if (DES_set_key(&key_data, &schedule) < 0)
{
printf("ERROR: %s", "DES Set Key Error!");
return NULL;
}
DES_ecb_encrypt(&xor_data, &buffer, &schedule, DES_ENCRYPT);
byte_array_ptr pin_block;
pin_block = (byte_array_ptr)malloc(sizeof(size_t) + 8);
pin_block->size = 8;
pin_block->data = (unsigned char *)malloc(pin_block->size);
memcpy(pin_block->data, &buffer, pin_block->size);
return pin_block;
}
and the decryption
byte_array_ptr des_decrypt_to_xor_bytes(byte_array_ptr key_bytes, byte_array_ptr pin_block)
{
if ((key_bytes->size != 8) || (pin_block->size != 8))
return NULL;
DES_key_schedule schedule;
const_DES_cblock key_data;
const_DES_cblock pin_data;
DES_cblock buffer;
memcpy(&key_data, key_bytes->data, key_bytes->size);
memcpy(&pin_data, pin_block->data, pin_block->size);
if (DES_set_key(&key_data, &schedule) < 0)
{
printf("ERROR: %s", "DES Set Key Error!");
return NULL;
}
DES_ecb_encrypt(&pin_data, &buffer, &schedule, DES_DECRYPT);
byte_array_ptr xor_bytes;
xor_bytes = (byte_array_ptr)malloc(sizeof(size_t) + 8);
xor_bytes->size = 8;
xor_bytes->data = (unsigned char *)malloc(xor_bytes->size);
memcpy(xor_bytes->data, &buffer, xor_bytes->size);
return xor_bytes;
}
but I have no idea how to do it for 3DES.
Any idea?

OpenSSL provides a set of functions for Triple DES in EDE mode(Encrypt using key #1, Decrypt using key #2, Encrypt using key #3) for all encryption schemes. Also its common situation when key #1 equals key #3, there are functions for this case either.
So if you have all three keys the functions are:
DES_ecb3_encrypt()
DES_ede3_cbc_encrypt()
DES_ede3_ofb_encrypt()
DES_ede3_cfb_encrypt()
If you have only two keys the functions are:
DES_ecb2_encrypt()
DES_ede2_cbc_encrypt()
DES_ede2_ofb_encrypt()
DES_ede2_cfb_encrypt()

Related

How to implement RSA Encryption in C?

I'm trying to use asymmetric encryption in a C program, to encrypt strings.
I chose to go with RSA, but if there's a less complicated yet secure way, do tell me.
OpenSSL is one library I've looked at and found no documentation on implementing it in C code. (I may just have been unlucky, I've been looking for many days)
No luck on YouTube/Google either...
Please point me to a detailed source of information on how how to do this...
I understand both C and the fundamental concepts of RSA pretty well, but I have no idea how to:
Generate the large primes needed to generate the keys.
Fix e = 65537 .
Generate the public / private keys in an alphanumeric format (they are actually numbers, arent they ?) .
Seamlessly combine (e,n) in the public key and (d,n) in the private key in the way tools like OpenSSL seem to do (in an alphanumeric string) .
Here's an example of what you're looking to do. First a utility function to print OpenSSL error messages:
void log_ssl_err(const char *mes)
{
unsigned long err, found;
char errstr[1000];
found = 0;
while ((err = ERR_get_error())) {
ERR_error_string(err, errstr);
printf("%s: %s", mes, errstr);
found = 1;
}
if (!found) {
printf("%s", mes);
}
}
Generating a key with a given exponent:
RSA *rsa;
BIGNUM *e;
uint32_t exponent_bin, exponent_num;
exponent_num = 65537;
exponent_bin = htonl(exponent);
e = BN_bin2bn((const unsigned char *)&exponent_bin, 4, NULL);
if (e == NULL) {
log_ssl_err("BN_bin2bn failed for e");
exit(1);
}
if ((rsa = RSA_new()) == NULL) {
log_ssl_err("RSA_new failed");
BN_free(e);
exit(1);
}
if (!RSA_generate_key_ex(rsa, 2048, e, NULL)) {
log_ssl_err("couldn't generate rsa key");
BN_free(e);
exit(1);
}
Encrypting and decrypting:
unsigned char plaintext[] = "this is the plaintext";
unsigned char *ciphertext, *decrypted;
int cipher_len, decrypted_len;
ciphertext = malloc(RSA_size(rsa));
if ((cipher_len = RSA_public_encrypt(strlen(plaintext), plaintext, ciphertext,
rsa, RSA_PKCS1_OAEP_PADDING)) == -1) {
log_ssl_err("RSA_public_encrypt failed");
exit(1);
}
decrypted = malloc(RSA_size(rsa));
if ((decrypted_len = RSA_private_decrypt(cipher_len, ciphertext, decrypted,
rsa, RSA_PKCS1_OAEP_PADDING)) == -1) {
log_ssl_err("RSA_private_decrypt failed");
return 0;
}
The documentation for OpenSSL can be difficult to navigate, but the information you need can be found in the man pages. If you run man 3 rsa you'll see a list of all the RSA related functions. From there you can look at the man page for each function.

How to get key usage values from X509 cert?

I need to retrieve information from x509 cert to verify Key usage. For example I need to make sure certificate can be used for digital signing (80).
It can be printed out by the following code piece, but i actually want to verify if certificate has a specific property. What i need is a method like boolean certHasAbility(X509 * cert, int purpose );, where purpose can be DigitalSignature(80) or Key Encipherment(20).
STACK_OF(X509_EXTENSION) *ext_list;
ext_list = cert->cert_info->extensions;
outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
if(sk_X509_EXTENSION_num(ext_list) <= 0)
return 1;
for (int i=0; i<sk_X509_EXTENSION_num(ext_list); i++) {
ASN1_OBJECT *obj;
X509_EXTENSION *ext;
ext = sk_X509_EXTENSION_value(ext_list, i);
obj = X509_EXTENSION_get_object(ext);
BIO_printf(outbio, "\n");
BIO_printf(outbio, "Object %.2d: ", i);
i2a_ASN1_OBJECT(outbio, obj);
BIO_printf(outbio, "\n");
X509V3_EXT_print(outbio, ext, NULL, NULL);
BIO_printf(outbio, "\n");
}
I would use X509_get_ext_d2i function:
static void print_my_key_usage(X509 *cert)
{
ASN1_BIT_STRING *usage = X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL);
if (usage && (usage->length > 0))
{
if (usage->data[0] & 0x80)
printf("digitalSignature\n");
....
if (usage->data[0] & 0x08)
printf("keyAgreement\n");
if (usage->data[0] & 0x04)
printf("keyCertSign\n");
if (usage->data[0] & 0x02)
printf("cRLSign\n");
}
}
You can find details of bits from RFC5280.
Because there can be more than 1 byte in the bit string,
you need to handle it someway in your function:
boolean certHasAbility(X509 *cert, int purpose)
{
ASN1_BIT_STRING *usage = X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL);
if (usage)
{
if (usage->length == 1)
{
return (usage->data[0] & purpose) == purpose;
}
else
{
// TODO: handle different lengths.
}
}
}

RSA-OAEP with SHA -256 key size 2048 bits using OpenSSL

I am trying to address a use case exactly same as How to encrypt data using RSA, with SHA-256 as hash function and MGF1 as mask generating function?, but I need a few more clarity on this.
The above query was raised in the year 2013. At that time the OpenSSL only supported SHA1 hash (hard coded) for OAEP padding. In the latest OpenSSL (1.0.2k), I can see that this is addressed by using the following API:
int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
const unsigned char *from, int flen,
const unsigned char *param, int plen,
const EVP_MD *md, const EVP_MD mgf1md)
RSA_public_encrypt() does not take EVP_MD structure as argument I'm not sure how to specify it.
How can I invoke the SHA-256 mode in RSA_public_encrypt() with a mask generation function?
RSA_public_encrypt(...) is deprecated; EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, ...) should be used instead.
Padding, mask generation function and other parameters are configured for the context which is passed as the first argument to EVP_PKEY_encrypt:
EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
if (evp_key == NULL) {
// handle error
}
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(evp_key, NULL);
if (ctx == NULL) {
// handle error
}
if (EVP_PKEY_encrypt_init(ctx) <= 0) {
// handle error
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) {
// handle error
}
if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, EVP_sha256()) <= 0) {
// handle error
}
if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, EVP_sha256()) <= 0) {
// handle error
}
if (EVP_PKEY_encrypt(ctx, encrypted, &outlen, data, len) <= 0) {
// handle error
}

decryption of MS office

I'm working on decryption of encrypted MS Excel(RC4 encryption with SHA1),password is already known.In vs2010,I've could decrypt it correctly,however,my program hasto work under both Win and linux.And I have no idea to get the encryption key under linux right now,which is something like below under Win:
int getEncrypKey(HCRYPTKEY *hKey, int blocknum)
{
//------------------------H0 = H(salt, password)-----
BYTE *pbSaltandPwdHash = NULL;
DWORD dwSaltandPwdLen = 0;
pbSaltandPwdHash = SHA1_2(psalt, 16, ppwd, strlen(pwd)/2, &dwSaltandPwdLen);
printf("SHA1 of SaltandPwd:\n");
for(DWORD i = 0 ; i < dwSaltandPwdLen ; i++) {
printf("%2.2x ",pbSaltandPwdHash[i]);
}
printf("\n");
//------------------------H0 = H(salt, password)-----
//------------------------Hfinal = H(H0, block)-----
HCRYPTHASH hHash1 = 0;
CryptCreateHash( hCryptProv, CALG_SHA1, 0, 0, &hHash1) ;
CryptHashData( hHash1, pbSaltandPwdHash, dwSaltandPwdLen, 0) ;
CryptHashData( hHash1, (unsigned char*)&blocknum, sizeof(blocknum), 0) ;
//------------------------Hfinal = H(H0, block)-----
CryptDeriveKey(hCryptProv, CALG_RC4, hHash1, 0x00280000, hKey);
if(hHash1 != 0) CryptDestroyHash(hHash1);
if(pbSaltandPwdHash != NULL) free(pbSaltandPwdHash);
return 0;
}
I knew how to get H0 under linux,but I dont know how to get the hHash1 and hKey.
This post sounds like it does the same thing: Implement Windows CryptoAPI CryptDeriveKey Using OpenSSL APIs
A more general way of generating hashes in openssl is below:
Before you do anything:
#include <ssl/evp.h>
int main(int argc, char argv[]) // or in an "initialise" type function
{
OpenSSL_add_all_digests()
...
}
Then to generate the hash (error checking omitted):
const EVP_MD *digest;
EVP_MD_CTX context;
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int hash_len;
digest = EVP_get_digestbyname("sha1"); /* choose the hash type here */
EVP_MD_CTX_init(&context);
EVP_DigestInit_ex(&contxt, digest, NULL);
EVP_DigestUpdate(&context, pbSaltandPwdHash, dwSaltandPwdLen);
EVP_DigestUpdate(&context, &blocknum, sizeof(blocknum));
EVP_DigestFinal_ex(&context, hash, &hash_len);
EVP_MD_CTX_cleanup(&context);
/* Now use hash and hash_len as required */

x509 certificate verification in C

I do have certificates in DER and PEM format, my goal is to retrieve the fields of Issuer and Subject and verify the certificate with the CA public key and simultaneously verify CA certificate with the root public key.
I am able to retrieve all the details of issuer and subject but unable to verify the certificate.
The API used:
x509 = d2i_X509_fp (fp, &x509); //READING DER Format
x509 = PEM_read_X509 (fp, &x509, NULL, NULL); //READING PEM Format
//to retrieve the Subject:
X509_NAME_oneline(X509_get_subject_name(x509), subject, sizeof (subject));
//to retrieve the Issuer:
X509_NAME_oneline(X509_get_issuer_name(x509), issuer, sizeof (issuer));
//To store the CA public key (in unsigned char *key) that will be used to verify the
//certificate (in my case always sha1WithRSAEncryption):
RSA *x = X509_get_pubkey(x509)->pkey.rsa;
bn = x->n;
//extracts the bytes from public key & convert into unsigned char buffer
buf_len = (size_t) BN_num_bytes (bn);
stored_CA_pubKey = (unsigned char *)malloc (buf_len);
i_n = BN_bn2bin (bn, (unsigned char *)stored_CA_pubKey);
if (i_n != buf_len)
LOG(ERROR," : key error\n");
if (key[0] & 0x80)
LOG(DEBUG, "00\n");
stored_CA_pubKeyLen = EVP_PKEY_size(X509_get_pubkey(x509));
For Verification I went through different approaches but I am unable to verify:
a)
i_x509_verify = X509_verify(cert_x509, ca_pubkey);
b)
/* verify the signature */
int iRet1, iRet2, iReason;
iRet1 = EVP_VerifyInit(&md_ctx, EVP_sha1());
iRet2 = EVP_VerifyUpdate(&md_ctx, cert_code, cert_code_len);
rv = EVP_VerifyFinal(&md_ctx, (const unsigned char *)stored_CA_pubKey,
stored_CA_pubKeyLen, cert_pubkey);
NOTE : cert_code and stored_CA_pubKey are unsigned char buffers.
I use following code for verifying a certificate
init CertStore:
X509_STORE* m_store = X509_STORE_new();
X509_LOOKUP* m_lookup = X509_STORE_add_lookup(m_store,X509_LOOKUP_file());
X509_STORE_load_locations(m_store, "CAFile.pem", NULL);
X509_STORE_set_default_paths(m_store);
X509_LOOKUP_load_file(m_lookup,"CAFile.pem",X509_FILETYPE_PEM)
// alternative lookup by hashdir
// X509_LOOKUP* m_lookup=X509_STORE_add_lookup(m_store,X509_LOOKUP_hash_dir());
VerifyCert:
X509_STORE_CTX *storeCtx = X509_STORE_CTX_new();
X509_STORE_CTX_init(storeCtx,m_store,cert,NULL);
X509_STORE_CTX_set_flags(storeCtx, X509_V_FLAG_CB_ISSUER_CHECK);
if (X509_verify_cert(storeCtx) == 1)
{
printf("success");
}
else
{
printf("Verificatione rror: %s",X509_verify_cert_error_string(storeCtx->error));
}
X509_STORE_CTX_free(storeCtx);
you also need to cleanup m_store
if(m_store != NULL)
{
X509_STORE_free(m_store);
m_store = NULL;
}
Take a look at my self-answered question: https://stackoverflow.com/questions/3412032/openssl-c-how-do-you-verify-a-public-key-was-issued-by-your-private-ca it goes a long way to doing what you need.
X509_STORE* m_store = NULL;
X509_LOOKUP *m_lookup = NULL;
X509_STORE_CTX *storeCtx = NULL;
m_store = X509_STORE_new();
if(NULL == m_store) goto exit;
m_lookup = X509_STORE_add_lookup(m_store, X509_LOOKUP_file());
if(NULL == m_lookup) goto exit;
X509_STORE_load_locations(m_store, CA_CERT_PATH, NULL);
X509_STORE_set_default_paths(m_store);
X509_LOOKUP_load_file(m_lookup,CA_CERT_PATH, X509_FILETYPE_ASN1);
m_lookup = X509_STORE_add_lookup(m_store, X509_LOOKUP_hash_dir());
if(NULL == m_lookup) goto exit;
storeCtx = X509_STORE_CTX_new();
if(NULL == storeCtx) goto exit;
X509_STORE_CTX_init(storeCtx,m_store,cer_x509,NULL);
X509_STORE_CTX_set_flags(storeCtx, /*X509_V_FLAG_CHECK_SS_SIGNATURE*/0x4000);
if (X509_verify_cert(storeCtx) == 1)
{
printf("success\n");
}
else
{
printf("Verification error: %s\n",X509_verify_cert_error_string(storeCtx->error));
}
exit:
if(NULL != storeCtx) X509_STORE_CTX_free(storeCtx);
if(m_store != NULL)
{
X509_STORE_free(m_store);
m_store = NULL;
}
After Doing this also I am unable to verify Self signed certificate

Resources