Double AES encryption with random key generation - c++

I am using 2 embedded GSM devices. There needs to send data between devices. Suppose I require to send the string "ring" from one device to another. It is a command and needs to be sent multiple times. 1st thing I do is keep the aes_key same in both devices. Then encrypt the input_data(that is "boom") and get the enc_buffer. Send this enc_buffer over socket to other device. The other device has same aes_key. Using that I decrypt the buffer received into dec_buffer. My doubt is that will the encrypted message enc_buffer be same every time I send the encrypted text for "boom". If it is same, then I need to follow another approach. I have a 1st level aes_key, that is constant. Then I need to generate a 2nd level aes_key. Encrypt the 2nd level aes_key and send it over socket. In the receiving device, decrypt it using 1st level aes_key to get the 2nd level aes_key. Store it. In 1st device again encrypt string "boom" using 2nd level aes_key, send it over socket. In the 2nd device decrypt the encrypted message using 2nd level aes_key to get text "boom". But another problem is how to generate the 2nd level aes_key in 1st device. Is there some random key generator API present in Linux. Or can I use random number generator API. I need a 10 character-length key. For that I call random number generator 10 times to generate a number between 0-26 and convert this to character. Then gather then together to get the desired key. I am using the AES code sample as below. Pasted for reference to above text.
unsigned char aes_key[]= "asytfuhcilejnco";
unsigned char input_data[]= "Sandeep";
int data_size= strlen((char*)input_data);
int buffer_size = ((int)(data_size/AES_BLOCK_SIZE) + 1)*AES_BLOCK_SIZE;
AES_KEY enc_key,dec_key;
unsigned char iv[AES_BLOCK_SIZE];
int main()
{
unsigned char enc_buffer[buffer_size+1];
unsigned char dec_buffer[buffer_size+1];
memset(iv,0x00,AES_BLOCK_SIZE);
AES_set_encrypt_key(aes_key,sizeof(aes_key)*8,&enc_key);
AES_cbc_encrypt(input_data,enc_buffer,sizeof(input_data),&enc_key,iv,AES_ENCRYPT);
enc_buffer[buffer_size+1]='\0';
memset(iv,0x00,AES_BLOCK_SIZE);
AES_set_decrypt_key(aes_key,sizeof(aes_key)*8,&dec_key);
AES_cbc_encrypt(enc_buffer,dec_buffer,sizeof(input_data),&dec_key,iv,AES_DECRYPT);
dec_buffer[buffer_size+1]='\0';
cout<<"input_data="<<input_data<<endl;
cout<<"enc_buffer="<<enc_buffer<<endl;
cout<<"dec_buffer="<<dec_buffer<<endl;
}
so, I have 3 questions
Is encrypted data always the same for same input_data and aes_key?
Is there any random key generator API?
What systemcall is there for random numbers in Linux c++?

Is encrypted data always the same for same input_data and aes_key?
No. It is the same for the same key, iv, & data.
Is there any random key generator API?
Yes, OpenSSL has one, for instance.
What systemcall is there for random numbers in Linux c++?
A "good" random number generator is /dev/urandom. Arguably better, if available, is /dev/hwrng, however it is different, not necessarily better. /dev/random is similar, possibly better to /dev/urandom but will block when sufficient entropy is not available.
In all cases you read these devices just as you would read data from a file.

enc_buffer[buffer_size+1]='\0'
Don't do that, this is a buffer overflow. The maximum index on both your buffers is [buffer_size].
memset(iv,0x00,AES_BLOCK_SIZE);
Don't do that, using the same iv (Initialization Vector) guarantees that your ciphertext will also be the same. For encryption, initialize the iv with random bits as Claris mentioned. For decryption you can ignore the iv output.

Related

What does binascii.hexlify(os.urandom(32)).decode() mean?

I'm trying to develop a function which would refresh token model in django rest framework.They seem to use binascii.hexlify(os.urandom(32)).decode() for generating unique tokens for every user.How does this line ensures that token generated by it will always be unique.Suppose if i want to refresh content of token after every 10 months ,then, will binascii.hexlify(os.urandom(32)).decode() will generate unique key that has not been used by any current user or i need to check whether it is being used or not?
help(os.urandom) says:
Return a bytes object containing random bytes suitable for cryptographic use.
On Linux this will use the /dev/urandom character device which is designed to be cryptographically secure. Only time it could fail to generate so would be the very early stage of boot when the entropy pool is not initialized yet 1. But once it's initialized and seeded from the previouse seed, device drives and so on you would generate cryptographic grade randomness.
Also check man 4 urandom.
1 getrandom(2) system call is there for these cases, which is blocking unlike reading from /dev/urandom.
binascii.hexlify(os.urandom(32)).decode():
os.urandom(32) returns 32 bytes of random data
binascii.hexlify returns the hex represntation of the bytes
as the return from hexlify is bytes we need to decode it to get string
So as the original random bytes are being retrieved from os.urandom this should be (cryptographically) secure randomness.

How to copy int to u_char*

I have a u_char* dynamic array having binary data of some network packet. I want to change the destination port number in the packet with some integer value. Suppose that the port number offset within the packet is ofs, with length of 4 bytes.
I tried the following 2 methods:
u_char* packet = new u_char[packet_size]; // Packet still empty
// Read packet from network ...
int new_port = 1234;
Method #1:
std::copy((u_char*)&new_port, (u_char*)&new_port+4, packet+ofs);
Method #2:
std::string new_port_str = std::to_string(new_port);
auto new_port_bytes = new_port_str.c_str();
std::copy(new_port_bytes, new_port_bytes+4, packet+ofs);
Both methods give garbage value for port number (but the rest of the packet is OK). Could anyone help me ?
You have to convert the integer from whatever internal representation your platform happens to use to the format the particular network protocol you're using requires them to be in when sent over the network.
This depends on the particular network protocol you're trying to use -- check its documentation for precisely the format it requires ports to be expressed in. My bet will be it's network byte order. You probably have functions like htons to convert shorts to network byte order.
Another problem -- how many bytes is int on your platform? How many bytes does the network protocol use to express ports? I'll bet the numbers are 4 and 2 respectively. So that's another issue. (Or maybe it isn't. I don't know for sure how many bytes an int is on your platform nor do I know what protocol you're trying to work with, so I have to guess.)
You can't just write code randomly and expect it to work. You have to think about what you're trying to do and understand the requirements.
My recommendation would be to look at the specification for the network protocol you're working with and figure out exactly which bytes in the data have to change and what they have to change to. Then write code to change each byte to the correct value according to the network protocol specification. This will ensure your code works correctly on any platform.

RSA Signature Size Mismatch

As stated here, the length of the message signature is equal to the modulus of the Private Key, aka the Public Key.
I'm implementing a system that signs a message, and I have a size mismatch that I can't solve.
I use crypto++.
Here is the code I use :
/* Create RSA Keys */
RSA::PrivateKey privateKey;
privateKey.GenerateRandomWithKeySize(prng, 3072);
RSA::PublicKey publicKey(privateKey);
cout << ">> RSA Keys generated";
/* Key Size */
string spki;
StringSink sSink(spki);
publicKey.Save(sSink);
cout <<" ("<< spki.size()<<" bytes)"<<endl;
RSASSA_PKCS1v15_SHA_Signer signer(privateKey);
size_t length = signer.MaxSignatureLength();
cout <<"MaxSignatureLength " <<length<<endl;
SecByteBlock signature( length );
And the output is :
>> RSA Keys generated (420 bytes)
>> ServerHello sent (436 bytes)
MaxSignatureLength 384
RSA Signature length 384
Shouldn't the MaxSignatureLength, and the RSA Signature length 420 bytes long ?
Is the problem with the algorithm I use ?
Shouldn't the MaxSignatureLength, and the RSA Signature length 420 bytes long ?
No. You are asking for a key with 3072-bits or 384 bytes. That's the limit on the size of the signature.
Each cryptosystem will likely be different in this area.
cout <<" ("<< spki.size()<<" bytes)"<<endl;
This is the size of {OID,n,e} with the ASN.1 framing or overhead. See your previous question Sending PublicKey within packet payload for what it looks like (in particular, the output of the command dumpasn1 rsa-public.der).
cout <<"MaxSignatureLength " <<length<<endl;
This is n - 1 for RSA, if I recall correctly.
Is the problem with the algorithm I use ?
No, you are doing things correctly by calling MaxSignatureLength().
>> RSA Keys generated (420 bytes)
>> ServerHello sent (436 bytes)
I'm just speculating, but it appears you appear to have design issues, too.
When you encrypt a message, like the ServerHello, you usually encrypt it under a symmetric cipher, like AES or Camellia. Then, you take that symmetric cipher key, and encrypt it under the RSA key. Finally, you send the pair {encrypted symmetric cipher key, encrypted message under symmetric cipher} to the other party.
In the system partially described above, you're only encrypting 16 or 32 bytes under the public key.
I think what you should be doing is using an Integrated Encryption Scheme to send encrypted message back and forth. For that, see Elliptic Curve Integrated Encryption Scheme (ECIES) and Discrete Logarithm Integrated Encryption Scheme (DLIES). ECIES operates over elliptic curves, and DLIES operate over integers.
Integrated Encryption Schemes have some very desireable security properties, like they are IND-CCA2. They achieve it by not allowing you to do some things, like reusing a security context, so the security is baked into the scheme.
You still have to solve the key distribution problem, though. That's a thorny problem, and we don't have a good, scalable solution.
And now you see why algorithm agility is important, and why you want that OID sent as part of the key during the handshake phase :)

Length of null terminated string in C/C++

I am using openssl to encrypt the string and i get null terminated string. I have now encrypted string and I want to send it over network with base64 encoding. I just need to send the encrypted data, how can I calculate the length of the string on the other side before decryption?
unsigned char *plaintext = (unsigned char*) "The quick brown fox jumps sover thes lazy dog";
unsigned char ciphertext[256] = {};
// After using openssl envelope_seal(), with EVP_aes_128_cbc()
strlen((const char*)ciphertext) // length is different each time due to null terminated binary string
sizeof(ciphertext) // lenght is equal to 256
int envelope_seal( ) // gives me the length of that string as 48.
Kindly help me to calculate the length of the ciphertext which is 48 but none of the method in my knowledge gives me the correct output.
AES is a block cipher. It has block size of 16 bytes - which means if you want to encrypt some data with it the length of the data in bytes must be multiple of 16 (if it is not you might need to use padding such as say PKCS7, more details).
Now after you encrypt a string with AES (say length of string is 32 bytes) - you can't use strlen anymore to get the length of the result, because the result, isn't a string anymore it is some byte array which represents the results of encryption. Actually you don't need to get the length anyway, it will be same size as plaintext - 32 bytes as we said in our case.
So I think you don't have issues with calculating length anymore - now if the other side should know length of the ciphertext you can send the length (say 32 in our case) in advance in packet. The other side should reconstruct the plain text now (and also remove padding bytes if one was used).
note: After you performed encryption and have the ciphertext you can apply base64 encoding to it and send it over, but you could as well send the byte array representing the ciphertext too.
In regard to comments, I will try to briefly highlight how this process goes. Say you have string char * str = "hello" - which is 5 bytes and you need to encrypt it. Like I said you can't encrypt it directly, you need to pad it to make multiple of 16. For this you can use PKCS7 padding (it is similar to PKCS5 but is for 16 bytes blocks). Now when you apply padding e.g., char * paddedText = PKCS7(str), you will end up with byte array which is 16 bytes.
Now, there is no more problem. You can encrypt this 16 bytes of plaintext. Result will also be 16 bytes cipher text.
Now if you want to decrypt this 16 bytes of cipher text, you can decrypt it directly (because it is multiple of 16). Now, due to the way PKCS7 padding works you will easily be able to tell from the result that only first 5 bytes were original string and you will remove 11 redundant bytes (how PKCS5 works, see in my link-PKCS7 is similar just for 16 byte block lengths), and obtain "hello".
Finally, I don't see where is the problem, when you send from client to server, you can just encode message length, e.g., 16 in packet, so that receiver knows 16 bytes represent cipher text. But again as I said, using this 16 bytes, the receiver, after decrypting will be able to determine that only first 5 bytes were original text (due to used padding PKCS7). So there is no need to send anything except 16; with help of PKCS padding scheme you will be able to tell that only first 5 bytes were plain text.
ps. After some discussions with OP it seems padding was not his main issue, because openssl method that was used seems to take care of that.
If the valid data in the array isn't terminated, then there's no way to tell its length by looking at the array.
If envelope_seal told you the length, then use that, passing it wherever the length is needed.
AES is a block cipher. Therefore the length of ciphertext will be the length of your plaintext modulo blocksize, rounded up to nearest blocksize.

Will TripleDes alter the Datasize

I have a code that encrpyts and decrypts the data using Triple DES.
Everything works fine with the code.
I have a query with the Triple Des.
Will Triple DES alter the data size while it does the encyption process.
I googled and was totally confused of the answers that i got.
will it alter. If Yes means how to find the size of the encrpyted data.
Here is the code :
unsigned char initVector[8];
unsigned char* block;
int j;
memset(initVector, 0xEE, sizeof(initVector));
nBlocks = dwDataSize / 8;
for (i=0; i < nBlocks; i++)
{
block = (unsigned char*) pData + i*8;
memset(initVector, 0xEE, sizeof(initVector));
des_ede3_cbc_encrypt((unsigned char *)block,(unsigned char *)block, 8,
m_Schedule1 , m_Schedule2, m_Schedule3, (C_Block *)initVector, DES_ENCRYPT);
I saw in another one discussion that the size will change.
Here is the link.
Length of Encrypted String
Regards,
Siva./
TripleDES is a block cipher primitive. Block ciphers work by creating a permutation of a block of input data (which is supposed to be indistinguishable from random data) based on a key, which can only be reversed if the key is known.
As such, the encrypted data occupies exactly the same amount of space as the input data (except perhaps for padding of the final block). Typical block sizes are any powers of two from 4 to 32 bytes.
(A thought experiment: It would be impossible for the cipher text to be shorter than the input, because then two distinct inputs would have to map to the same cipher text, which is impossible. Conversely, if the cipher text were longer, then there would be certain cipher texts than can never be the result of an encryption, thus not being "indistinguishable from random data".)
It depends. To be more precise, it depends on the following elements:
the encoding of the cipher text and plain text
the encryption mode
the padding mode & block size
the NONCE or IV
the (optional) authentication tag
3DES is a block cipher. It is a seemingly random permutation on bits (mostly using bytes as minimum element). A single 3DES uses 64 bit/8 bytes as input and generated the same size
To start with the first one: if you encrypt a piece of text (a character string) then you need to encode the string to bytes first. If you expect the cipher text to be stored in a string, you will need to convert the result into a string.
Next is the encryption mode: if this is a mode that converts the 3DES block cipher into a stream cipher (e.g. CTR) then the input size is identical to the output size, excluding the NONCE.
Then there is padding mode. If you use ECB or CBC mode encryption then you must pad if the plain text has length x, x % n != 0 and n is the block size in bytes. If you can distinguish the plain text from the padding, then you can add 0 to n - 1 bytes of padding. If you cannot, then you need to always pad, adding 1 to n bytes of padding. PKCS#5 padding (the most common one) always pads.
Normally you need to transfer the IV or NONCE as well. Both of them are normally about the same as the block size. A common option is to prepend the IV to the cipher text. This is often performed for CBC mode encryption which you apply. The only time you should not create a new (random) IV is when you use the key only a single time.
Most of the time you should add integrity protection to cipher text. If you use e.g. GCM mode encryption, then you need some additional space for the authentication tag. If you use a MAC or HMAC then this should be included on top of the cipher text.
There is also such a thing as cipher text stealing, which can be used to do away with padding. Finally, you may not need an IV for certain modes of single block encryption.
In your case:
If you work with bytes, use CBC mode encryption, prepend the IV and use PKCS#5 padding then the calculation would be (n) + ((x) + (n - x % n)). For 3DES, n = 8.