1

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.

Kahn
  • 755
  • 3
  • 11
  • 28
  • 1
    Why don't you send the length with the string itself? – Bartek Banachewicz Feb 05 '15 at 17:08
  • I don't know in detail about cryptography, but if i need to send encrypted document, then where do I put the length? Document isn't enough? – Kahn Feb 05 '15 at 17:14
  • "send encrypted document". Normally when one talks about a "document", a char array containing raw binary data is not something that immediately comes to mind. If you have the latter, you do need the length. If you have a "document", you first clarify what that word actually means. – n. m. could be an AI Feb 05 '15 at 17:27
  • You calculate the length in the code that generates the information. You've replaced that code with a comment, making it impossible to show you how to fix that code to pass on the length. – David Schwartz Feb 05 '15 at 18:01
  • Is the a C question or a C++ question? The answers can be very different for the two languages. For example, a C++ solution might be to use a "blob" class or vector class, but C doesn't have classes. – David Schwartz Feb 05 '15 at 18:02

3 Answers3

4

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.

Community
  • 1
  • 1
Giorgi Moniava
  • 27,046
  • 9
  • 53
  • 90
  • +1 for discussion about the padding issues, which, IMO is crucial to extracting the string length from a block cypher which restricts length to multiples of 16. – chux - Reinstate Monica Feb 05 '15 at 18:21
  • @chux: Indeed when cipher requires input to be multiple of say 16 bytes, when you make plaintext multiple of 16 (if it is not) and encrypt it - then once you try to decrypt the cipher text you need to know how many bytes were in original string, that is where pkcs5 comes for instance – Giorgi Moniava Feb 05 '15 at 18:26
  • How do I know at the other end how long the encrypted data is? Do I have to send the length with it? What do you suggest? – Kahn Feb 05 '15 at 19:05
  • @gio I think OP needs sample (pseudo) code to show how to encode the string length and how to decode it. – chux - Reinstate Monica Feb 05 '15 at 19:20
  • 1
    @chux: I added more explanation, hope it is more clear? – Giorgi Moniava Feb 05 '15 at 19:34
  • @Hesper: it might be the library you are using, automatically applies padding, in that case you only need to send cipher text length e.g. 16 in our case, and the library will take care of padding; in that case library should also tell you length of cipher text – Giorgi Moniava Feb 05 '15 at 19:52
  • Thank you very much for such a detailed answer. I have 16 fields in database which I will encrypt, and then send over the network with base64 encoding. I need 16 more fields to store the length information. This is what I understood about my problem. – Kahn Feb 05 '15 at 20:14
  • @Hesper: to encode the length you might need only for the network protocol; e.g to distinguish in packet which part is ciphertext. The length of original text you shoul be able to tell from padding, no need to store that – Giorgi Moniava Feb 05 '15 at 20:34
  • perhaps still its not clear. I have a encrypted byte array, i cannot use strlen on that. How to know how long is the string where I put the ciphertextlen in envelope_open()? – Kahn Feb 05 '15 at 20:48
  • @Hesper: Say you want to encrypt "hello". Length is 5 bytes right? You can't encrypt it(because it is not multiple of 16). If you pad it, it will become 16 bytes. Now, if you encrypt it the length of cipher text will be same as plain text(because it is multiple of 16). So you see there is no problem to get length of the ciphertext, it is same as length of plain text if the length of the plain text is multiple of 16. – Giorgi Moniava Feb 05 '15 at 21:08
  • @Hesper: You can have a look at this article too: http://www.codeproject.com/Articles/831481/File-Encryption-Decryption-Tutorial-in-Cplusplus. – Giorgi Moniava Feb 05 '15 at 21:09
  • I understand about padding. but when you send an encrypted text from client, the server has to decrypt it using int envelope_open( ciphertextlen ) with one parameter as length of the encrypted text. How i can calculate this length. this is the problem. – Kahn Feb 05 '15 at 21:14
  • @Hesper: Hesper like I said if plaintext length was multiple of 16 the length of ciphertext is same as length of plaintext – Giorgi Moniava Feb 05 '15 at 21:19
  • Okay, but how do server knows about the length of plaintext? Client is only sending ciphertext to server, not plaintext – Kahn Feb 05 '15 at 21:21
  • @Hesper: Let's say client send cipher text whose length is 16 bytes. Then the length of plain text is also 16 bytes. (But using padding you might need to remove the redundant bytes from this 16 bytes, like the 11 bytes from the "hello" example - but for this you don't need to store the length anywhere, the Padding will help you do this automatically). – Giorgi Moniava Feb 05 '15 at 21:24
  • @Hesper: But if plain text length is not multiple of 16 you might have to make it multiple of 16 first, and then encrypt it and send the ciphertext. – Giorgi Moniava Feb 05 '15 at 21:25
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/70339/discussion-between-hesper-and-gio). – Kahn Feb 05 '15 at 21:25
1

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.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • I have a database where I need to store encrypted values. Do I have to store the length of each attribute with that attribute? There is no other way? – Kahn Feb 05 '15 at 17:16
  • @Hesper: Yes, if you want to store an arbitrary length of arbitrary data, you'll have to specify the length. – Mike Seymour Feb 05 '15 at 17:36
1

AES is a block cipher. Therefore the length of ciphertext will be the length of your plaintext modulo blocksize, rounded up to nearest blocksize.

inetknght
  • 4,300
  • 1
  • 26
  • 52
  • I am assuming the case where I don't have the plain text, and I have to decode the encrypted text – Kahn Feb 05 '15 at 19:14
  • 1
    Well when going reverse (you're given base64 data and you need to decode and decrypt it), then just allocate a buffer the size of base64 data. The decoded (still encrypted) data will be the same size or smaller as the base64-encoded data. Base64 decoding should tell you the size of the `ciphertext` and therefore you know exactly how long the `plaintext` is (which will still be a multiple of AES blocksize). You'll then need to figure out how long your plaintext "relevant" data is either by knowing the padding type or whether there's a size field or a null terminator or whatnot. – inetknght Feb 05 '15 at 19:18