Problem by Encryption & Decryption of text with EVP_des_ofb(), openSSL , C - c

I need to encrypt and decrypt txt-file with DES-ofb (libcrypto) using OpenSSL library, the key and Init Vector is given in one bin.file(key+iv). But after the decryption via EVP_DecryptUpdate(), decrypted text and plain text are not similar at all.
So I read plain.txt 8 bytes and a 'keyandIV.bin' files. Than I took first 8 bytes from keyandIVbuffer as a KEY for DES and the rest as IV. So I have 8 bytes key and 8 bytes IV, added '\0' at the end of both (Do I need '\0' here ? Key length must be 64 or 56 bits?).
This is my code for ercryption with DES ofb:
printf("ENCRYPTION:\n");
int howmany = 0, final1;
const EVP_CIPHER *CIPHER_TYPE = EVP_des_ofb();
EVP_CIPHER_CTX *ctx_encrypt = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx_encrypt);
EVP_EncryptInit(ctx_encrypt, CIPHER_TYPE, keybuf1, ivbuf1);
if(!EVP_EncryptUpdate(ctx_encrypt, ciphertextbuf1, &howmany, plaintextbuf1, plainlength1))return -1;
if(!EVP_EncryptUpdate(ctx_encrypt, ciphertextbuf1, &howmany, plaintextbuf1, plainlength1)) return -1;
EVP_EncryptFinal_ex(ctx_encrypt, ciphertextbuf1 + howmany , &final1);
EVP_CIPHER_CTX_cleanup(ctx_encrypt);
Than I took the encrypted buffer und decrypt it so:
printf("DECRYPTION:\n");
int final2;
EVP_CIPHER_CTX *ctx_decrypt = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx_decrypt);
EVP_DecryptInit(ctx_decrypt, CIPHER_TYPE, keybuf1, ivbuf1);
if(!EVP_DecryptUpdate(ctx_decrypt, decryptedtext, &howmany, ciphertextbuf1, strlen(ciphertextbuf1))) return -1;
if(!EVP_EncryptFinal_ex(ctx_decrypt, decryptedtext + howmany, &final2)) return -1;
EVP_CIPHER_CTX_cleanup(ctx_decrypt);
I definetly have understanding problem with DES. Maybe I did something wrong by creatimg key and IV from one file.I have seen plenty of examples but I still don't understand what I did wrong in my program.

The decryption sequence is EVP_DecryptInit_ex(), EVP_DecryptUpdate() and EVP_DecryptFinal_ex(). This follows EVP_EncryptInit_ex(), EVP_EncryptUpdate() and EVP_EncryptFinal_ex(). In your code you are calling EVP_EncryptFinal_ex() to decrypt, so obviously that's not going to work. Also, if something went wrong during an operation an error code should have been printed out to stderr.

Related

OpenSSL EVP_aes_128_cbc decryption got unexpected result

I encrypted a string with EVP_aes_128_cbc cipher, then changed the 1st byte of the ciphertext, and decrypt this changed ciphertext. Unexpectly, it didn't decrypt error or get a fully wrong result, but got a wrong 1st 16 bytes and same string of rest. Here is the encrypt func:
int do_crypt1(unsigned char *in, unsigned char *outbuf, int inlen, int do_encrypt)
{
unsigned char inbuf[1024];
int outlen;
EVP_CIPHER_CTX *ctx;
/*
* Bogus key and IV: we'd normally set these from
* another source.
*/
unsigned char key[32] = "test";
unsigned char iv[] = "1234567812345678";
/* Don't set key or IV right away; we want to check lengths */
ctx = EVP_CIPHER_CTX_new();
EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, NULL, NULL,
do_encrypt);
OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);
/* Now we can set key and IV */
EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, do_encrypt);
int update_len = 0;
for (;;) {
memcpy(inbuf, in, inlen);
if (inlen <= 0)
break;
if (!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)) {
/* Error */
EVP_CIPHER_CTX_free(ctx);
return 0;
}
update_len += outlen;
if(inlen <= 1024)
break;
}
if (!EVP_CipherFinal_ex(ctx, outbuf+outlen, &outlen)) {
/* Error */
EVP_CIPHER_CTX_free(ctx);
return 0;
}
EVP_CIPHER_CTX_free(ctx);
update_len += outlen;
return update_len;
}
and in the main:
unsigned char* b = (unsigned char*)malloc(1024);
unsigned char* hmac_code = (unsigned char*)malloc(1024);
int len = do_crypt1(value, hmac_code, strlen(value), AES_ENCRYPT);
printf("%s\n", value);
for (i = 0; i < len; i++)
printf("%x", *(hmac_code + i));
printf("\n");
printf("%d\n", len);
// printf("%s\n", hmac_code);
*hmac_code = 0x23;
len = do_crypt1(hmac_code, b, len, AES_DECRYPT);
printf("%d\n", len);
printf("%s\n", b);
free(hmac_code);
free(b);
result
Could anyone give me the reason and how to resolve this?
Actually as long as your plaintext is at least 17 bytes, the first 17 decrypted bytes should be wrong -- but since you're displaying the invalid decryption as text, some of the bytes may be invisible: in your example, the output is 2 chars shorter, so clearly 2 chars of the first 17 aren't visible. That's the expected result for damage in (at the beginning of) the first block of a 2-block (or more) CBC ciphertext for a 16-byte-block cipher like AES; see the diagram in wikipedia to understand why.
If you want detection of damage to the ciphertext, don't use CBC mode, or at least don't use it alone. Common/standard solutions nowadays are:
add authentication, such as HMAC. (Intriguingly your code already uses the variable name hmac_code even though you don't do anything even remotely related to HMAC.)
use an authenticated-encryption mode, like GCM, which effectively combines encryption and (some type of) MAC internally. Most authenticated modes today, including GCM, also support 'additional' or 'associated' data that is authenticated but not encrypted, and as a result are called AEAD, but you may or may not care about that.
use an error-propagating mode. These were popular decades ago, around the time of presidents Nixon, Ford, Carter, and Reagan, but are now mostly considered obsolete and are not directly supported by OpenSSL.
Also, BTW, your code is completely pants for values longer than 1024 bytes, which your test clearly doesn't exercise. First of all you don't need to break up such a value into chunks at all, but if for some reason you want to, the method you implemented is wrong.
Plus, the IV for CBC should be different and unpredictable every time; using a hardcoded value like this exposes you to two different classes of attacks. In general the advice you will get on Stacks actually related to security is 'don't roll you own'. Cryptographic code written by people who don't know what they're doing, even if/when it produces the correct output, is usually insecure. This is the major difference between crypto/security software and others; you can easily see if your editor or spreadsheet or database produces correct or incorrect output, and as long as the output is correct that's usually all you need, but you can't tell by looking at the output from an encryption/decryption program whether it is secure or not.

Encrypt bytes in a C struct, using OpenSSL RC4

TL;DR...
I need to encrypt an in-RAM C struct, byte-for-byte, using OpenSSL / EVP RC4 stream-cipher. How do I implement EVP (e.g. EVP_CipherUpdate) to accomplish the actual encryption of bytes in the struct?
The Details...
I have a ISAM/BTree database that needs its records/data encrypted. Don't worry about that, just know that each "record" is a C struct with many members (fields). This has been working for like 15 years (don't ask, the codebase is from the K&R C days, I think). The ISAM overhead simply takes a bytestream (the struct w/data) as an argument when writing the record... specifically, the ISAM's "write" function accepts a pointer to the data/structure.
Anyway, I'm trying to implement an OpenSSL stream cipher (RC4) -via the EVP framework- that can just sit between my program and the ISAM, so as to simply hand the ISAM my encrypted bytes, without him knowing or caring. I might add that I think the ISAM doesn't care about the structure of the data or even that it's a struct... it just gets raw data, I believe.
My struct is like this simplified example (in reality there are many more varied members):
typedef struct
UCHAR flag;
char field2[30];
int qty;
} DB_REC;
How would I (if it's even possible) go about encrypting the entire structure (in-place, even), byte for byte, if necessary? I've tried testing with simple strings, even; but can't get that to work, either.
I have another file called crypto.c (and .h) where I'm building my functions to encrypt and decrypt whatever I "pass" to them (might be a string, a struct, whatever - that's why my arg is void). For example:
void encrypt_db_rawData(void *data_to_encrypt, size_t data_size)
{
unsigned char buf_out[data_size];
int buf_out_byteCount = 0;
buf_out_byteCount = sizeof(buf_out);
EVP_CIPHER_CTX ctx; //declare an EVP context
int keyBytes = 16; //size of RC4 key in bytes
/* ... my_keystr is acquired from a file elsewhere ... */
/* ... my_iv is a global defined elsewhere ... */
EVP_CIPHER_CTX_init(&ctx);
EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1);
EVP_CIPHER_CTX_set_key_length(&ctx, keyBytes);
EVP_CipherInit_ex(&ctx, NULL, NULL, my_keystr, my_iv, 1);
int byte_i;
for( byte_i = 0; byte_i < sizeof(data_to_encrypt); i++ )
{
EVP_CipherUpdate(&ctx, buf_out, &buf_out_byteCount, data_to_encrypt[byte_i], 1);
}
*data_to_encrypt = buf_out; //overwrite the original data with its encrypted version
}
C is not my first language ~ especially C89 (or older perhaps), and I'm in way over my head on this one - this got thrown into my lap due to some restructuring; so I appreciate any constructive help anyone can offer. I'm in pointer-HELL!

aes-gcm using libgcrypt api in C

I'm playing with libgcrypt (v1.6.1 on Gentoo x64) and i've already implemented (and tested thorugh the AEs test vectors) aes256-cbc and aes256-ctr. Now i am looking at aes256-gcm but i have some doubt about the workflow. Below there is a skeleton of a simple encryption program:
int main(void){
unsigned char TEST_KEY[] = {0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4};
unsigned char TEST_IV[] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
unsigned char TEST_PLAINTEXT_1[] = {0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a};
unsigned char cipher[16] = {0};
int algo = -1, i;
const char *name = "aes256";
algo = gcry_cipher_map_name(name);
gcry_cipher_hd_t hd;
gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_GCM, 0);
gcry_cipher_setkey(hd, TEST_KEY, 32);
gcry_cipher_setiv(hd, TEST_IV, 16);
gcry_cipher_encrypt(hd, cipher, 16, TEST_PLAINTEXT_1, 16);
char out[33];
for(i=0;i<16;i++){
sprintf(out+(i*2), "%02x", cipher[i]);
}
out[32] = '\0';
printf("%s\n", out);
gcry_cipher_close(hd);
return 0;
}
In GCM mode there want also these instruction:
gcry_cipher_authenticate (gcry cipher hd t h , const void * abuf , size t abuflen )
gcry_error_t gcry_cipher_gettag (gcry cipher hd t h , void * tag , size t taglen )
So the correct workflow of the encryption program is:
gcry_cipher_authenticate
gcry_cipher_encrypt
gcry_cipher_gettag
But what i haven't undestood is:
abuf is like a salt? (so have i to generate it using gcry_create_nonce or similar?)
If i want to encrypt a file, void *tag is what i have to write to the outfile?
1) gcry_cipher_authenticate is for supporting authenticated encryption with associated data. abuf is data that you need to authenticate but do not need to encrypt. For example, if you are sending a packet, you might want to encrypt the body, but you must send the header unencrypted for the packet to be delivered. The tag generated by the cipher will provide integrity for both the encrypted data and the data sent in plain.
2) The tag is used after decryption to make sure that the data has not been tampered with. You append the tag to the encrypted text. Note, that it is computed on encrypted data and associated (unencrypted) data, so you will need both when decrypting.
You can check these documents for more information on GCM:
http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
Also, you can probably get faster answers to cryptography questions like this on http://crypto.stackexchange.com.

How to encrypt/decrypt long input messages with RSA? [Openssl, C]

I wrote a simple test program that encrypts/decrypts a message.
I have a keylength:
int keylength = 1024; // it can also be 2048, 4096
and max input length:
int maxlen = (keylength/8)-11;
and I know that my input size should be < than maxlen, something like this:
if(insize >= maxlen)
printf("cannot encrypt/decrypt!\n");
My question is simple - is it possible (if so, how can I do this) to encrypt/decrypt with RSA messages LONGER than maxlen?
Main code is also, very simple but works only when insize < maxlen:
if((encBytes=RSA_public_encrypt(strlen(buff1)+1, buff1, buff2, keypair, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
if((decBytes=RSA_private_decrypt(encBytes, buff2, buff3, keypair, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
Encrypting long messages requires combined scheme - RSA algorithm encrypts session key (i.e. AES key), and data itself is encrypted with that key.
I would recommend to not invent another bicycle and use well established scheme, i.e. PKCS#7/CMS or OpenPGP, depending on your needs.
You would be able to encrypt long messages with RSA the same way as it is done with block ciphers. That is, encrypt the messages in blocks and bind the blocks with an appropriate chaining mode. However, this is not the usual way to do it and you won't find support for it (RSA chaining) in the libraries you use.
Since RSA is quite slow, the usual way to encrypt large messages is using hybrid encryption. In hybrid encryption you use a fast symmetric encryption algorithm (like AES) for encrypting the data with a random key. The random key is then encrypted with RSA and send along with the symmetric key encrypted data.
EDIT:
As fore your implementation, you have insize = 1300 and keylength = 1024 which gives maxlen = 117. To encrypt the full message you those needs 12 encrypts, that each produce 128 bytes, giving an encrypted size of 1536 bytes. In your code you only allocates buffers of 1416 bytes. Also, you don't seem to allow for 128 bytes output as you only increment with 117 in:
RSA_public_encrypt(maxlen, buff1+i, buff2+i, keypair, RSA_PKCS1_PADDING)
and
i += maxlen;
You can use RSA as block cipher in that case. That is break the message to several blocks smaller than maxlen.
Otherwise impossible.
If you want to run RSA in a "block cipher" kind of mode, you would need to run it in a loop.
Like most of the other commenters, I'd like to point out that this is a bad use of RSA - You should just encrypt a AES key with RSA then use AES for the longer message.
However, I'm not one to let practicality get in the way of learning, so here's how you'd do it. This code isn't tested, since I don't know what libraries you are using. It's also a little overly-verbose, for readability.
int inLength = strlen(buff1)+1;
int numBlocks = (inLength / maxlen) + 1;
for (int i = 0; i < numBlocks; i++) {
int bytesDone = i * maxlen;
int remainingLen = inLength - bytesDone;
int thisLen; // The length of this block
if (remainingLen > maxlen) {
thisLen = maxlen;
} else {
thisLen = remainingLen;
}
if((encBytes=RSA_public_encrypt(thisLen, buff1 + bytesDone, buff2 + bytesDone, keypair, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
// Okay, IDK what the first parameter to this should be. It depends on the library. You can figure it out, hopefully.
if((decBytes=RSA_private_decrypt(idk, buff2 + bytesDone, buff3 + bytesDone, keypair, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
}
maxlen actually depends on a key length and padding mode. Think newer padding scheme ´OAEP´ e.g. in Java Encryption Engine takes additional 42 bytes instead of 11. Known libraries are not designed for using RSA in a block cipher mode.
For that purpose, beyond fragmentation as answered above, security aspects require further modification of the padding scheme, e,g, https://crypto.stackexchange.com/a/97974/98888

8 byte missing on EVP_DecryptFinal

this is my first question so please tell me if I do something wrong :).
My problem is I use
EVP_DecryptInit(&ctx1, EVP_des_ecb(), tmpkey, NULL);
EVP_DecryptUpdate(&ctx1, keysigout, &outlu ,keysigin, keysigfilelength);
EVP_DecryptFinal(&ctx1, keysigout, &outlf);
printf("DECLEN:%i",outlu + outlf);
to decrypt a binary file. The file is 248 bytes long but the printf only tells me EVP decrypted 240 bytes. keysigfilelength is 248 and should tell the update that 248 bytes need to be decrypted.
I dont understand why this doesnt work and would be happy if you can enlighten me.
Edit:
I just encrypted a file manually with the command
openssl enc -e -des-ecb -in test.txt -out test.bin -K 00a82b209cbeaf00
and it grew by 8 bytes :O. I still don't know where they come from but I don't think the general error I have in my program is caused by this.
The context of this whole problem is an information security course at my university. We got similar Tasks with different algorithms, but even someone who has done his program successfully couldnt figure out where the problem in my program is.
Is it ok to post my whole program for you?
I hope its fine to answer my own question.
EVP_DecryptUpdate(&ctx1, keysigout, &outlu ,keysigin, keysigfilelength);
EVP_DecryptFinal(&ctx1, keysigout + outlu, &outlf);
The problem was the missing outlu, DecryptFinal tried to decrypt the whole block again. When i added the outlu i got 7 byte in outlf, and it worked.
For future reference i add the whole function below.
It expects the key and iv to be one block of data.
int decrypt(const EVP_CIPHER *cipher,unsigned char *key, unsigned char *encryptedData, int encryptedLength,unsigned int * length, unsigned char ** decryptedData)
{
int decryptedLength = 0, lastDecryptLength = 0, ret;
unsigned char * iv = NULL;
EVP_CIPHER_CTX *cryptCtx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(cryptCtx);
*decryptedData = malloc (encryptedLength * sizeof(char));
if(cipher->iv_len != 0) iv = key + cipher->key_len;
EVP_DecryptInit_ex(cryptCtx, cipher, NULL, key, iv);
EVP_DecryptUpdate(cryptCtx, *decryptedData, &decryptedLength, encryptedData, encryptedLength);
ret = EVP_DecryptFinal_ex(cryptCtx, *decryptedData + decryptedLength, &lastDecryptLength);
*length = decryptedLength + lastDecryptLength;
EVP_CIPHER_CTX_free(cryptCtx);
EVP_cleanup();
return ret;
}
Because block ciphers only really want to work on an input that is a multiple of their block size, the input is normally padded to meet this requirement.
The default for many programs (including openssl enc is to use PKCS #5 padding
If the plaintext is not a multiple of 8 bytes then padding bytes are added so that it is. If it is already a multiple of 8 bytes then 8 bytes of padding are added. Thus it is entirely normal for the encrypted data to be longer than the plaintext.

Resources