4
\$\begingroup\$

I am trying to encrypt/decrypt file using source code directly. The issue is how to properly do it after reading the file.

int crypto_aead_encrypt(
    unsigned char *c, unsigned long long *clen,
    const unsigned char *m, unsigned long long mlen,
    const unsigned char *ad, unsigned long long adlen,
    const unsigned char *nsec,
    const unsigned char *npub,
    const unsigned char *k
)

Working code: (plaintext is char *)

for (start = 0; start < fileLength; start += 32)
    {
        int end = (start + 32);
        end = end > fileLength ? fileLength : end;

        strncpy(msg, plaintext + start, end - start);

        // encrypt
        crypto_aead_encrypt(ct, &clen, msg, mlen, ad, adlen, NULL, nonce, key);

        // decryption

        crypto_aead_decrypt(msg2, &mlen2, NULL, ct, clen, ad, adlen, nonce, key);
}

This is the function, and the max limit of the message m is 32 bits, which would make encrypting/decrypt very long for large files (ex. 1GB). Is there a way to perform the encrypting as fast as if it were from the library. Neglecting the code above, ex. how does OpenSSL do it when -in is provided?

The way I have it is to read the file, save it to an char * and then take 32 bits and enc each one. So I am wondering if there is a proper more correct way to do it.

Edit: reference implementation like ascon or photon-beetle

\$\endgroup\$
2
  • \$\begingroup\$ Why do you first read the entire file, and more importantly, why do you only encrypt 32 bits / 4 bytes at a time? That don't make no sense at all. \$\endgroup\$ Apr 15, 2020 at 22:53
  • \$\begingroup\$ @MaartenBodewes 32 bits cause that's the max the algorithm accepts (max msg size for encrypting/decrypting blocks). And I'm not sure how else to do it without reading the entire file first, I read it and store it then process the stored \$\endgroup\$ Apr 16, 2020 at 1:48

2 Answers 2

2
\$\begingroup\$

I think you're confused here. The GCM algorithm has a 96 bit nonce, and fills the rest of the 128 bit block size with a 32 bit counter. So you have 2^32 full blocks at your disposal, or about 64 GiB. That's - uh - slightly more than 32 bits (well, OK, the counter starts at 2, so you'd have 48 bytes less than that, better keep it at 32 GiB or 48 GiB).

\$\endgroup\$
4
  • \$\begingroup\$ Thanks! how do you suggest to do it then? I mean encrytping the plaintext directlt? I tried that but I kept getting error due to exceeding the limit. For example I am using photon-beetle and particularly this as a tempalte to do the enc/dec where the max is 32 \$\endgroup\$ Apr 16, 2020 at 13:17
  • \$\begingroup\$ I'm not entirely sure what goes wrong; I'd have to debug the code for that. I can see in the photon code that size_t Dlen_inblocks = (Dlen_inbytes + RATE_INBYTES - 1) / RATE_INBYTES; which splits up the input as 4 byte blocks. That's not something you do if the total input can be 32 bits (which makes no sense whatsoever for an AEAD cipher). \$\endgroup\$ Apr 16, 2020 at 13:51
  • \$\begingroup\$ Ah ok, and the other thing that the crypto_aead_encrypt takes in m as a unsigned char so that means after it passes there it's converted to uint8_t (const uint8_t *Data_in). In any case, I even tried again sending fill plaintext and the fill length but it's a buffer overflow due to the full plaintext I'm pretty sure Edit: I changed the code and was able to get it to work! however, not for large files (ex. 16mb), a stack overflow. I'm currently really stuck on where or how I could fix it though, tried different ways to debug it but no success so far \$\endgroup\$ Apr 16, 2020 at 20:15
  • \$\begingroup\$ I guess the error shows the place where these kind of questions are more on topic :) Glad you got the initial issue solved. What I wrote was for GCM (which I wrongly assumed was the block cipher), if there is a block of 4 bytes then of course the algorithm may have different limits. You can e.g. split up the file in chunks and encrypt them separately. You'd have to create a MAC over the authentication tags though, otherwise the chunks may be reordere.d by an adversary. \$\endgroup\$ Apr 17, 2020 at 0:13
2
\$\begingroup\$

So I am wondering if there is a proper more correct way to do it.

binary data

An encryption of a file should not assume it is text lacking a '\0'. As a binary file, data may include null characters which will incorrectly copy using strncpy().

// strncpy(msg, plaintext + start, end - start);
memcpy(msg, plaintext + start, end - start);

LARGE files

"for large files (ex. 1GB)" --> 1GB is not so large. Rather than limit file size to the int range, use size_t. That is typicality at least 2x the positive range or perhaps billions x. Code is limited in design to size_t given the usage of a single array. Might as well use as much range as possible.

size_t start;
... 
// int end = (start + 32);
size_t end = (start + 32);

Better code would use unsigned long long like the int crypto_aead_decrypt(unsigned char* m, unsigned long long* mlen, ...) signature.

\$\endgroup\$
1
  • \$\begingroup\$ Good point about the int. It made no sense for 32 bit input, but for larger input e.g. a 2 GiB - 1 max size may be prohibitive. The strncpy is interesting as well; I presumed readable text when I saw that, but that might be a somewhat presumptuous :) \$\endgroup\$ Apr 18, 2020 at 14:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.