How does AESCrypt handle the initialization vector (IV) for file format 2?
It seems like you cannot specify an IV when generating a file... so I'm assuming that the IV is stored unencrypted next to the ciphertext?
It's open source. I took a quick look at the code and it wasn't immediately clear.
This link references an IV1... but it's not fully clear. Where does IV1 come from?
I just did a bit of looking around at it, and I do understand it for the most part. I'll answer your questions as best I understand them.
1) AESCrypt uses 2 IVs per encryption. They have one key, IV pair used to encrypt the bulk of the message, and these are Key2 and IV2, and they also have a key, IV pair used only to encrypt Key2 and IV2, and these are called Key1 and IV1. Key1 is of course not part of the encrypted file, but IV1 is indeed stored unencrypted in the 16 octets near the bottom of the gray box you linked. The 48 octets right after that are Key2 and IV2 which are encrypted. It is OK for the IV (especially IV1) not to be encrypted. It is there to make it nearly impossible for the same 16-byte data block to look the same every time it appears in the cipher text. But there is no need at all for the IV to be secret. I am actually surprised they keep IV2 secret (encrypted) but there is no harm in their doing that.
2) Yes, I guess I answered this one already, but IV1 is unencrypted in the 16 octets chunk of the file per format 2 specification, and IV2 is encrypted with Key2 in the 48 octets right after.
3 &4 I will answer together. You may have seen IV2's function, which is just a random function generating bytes directly. IV1 is generated in a more complex way. I will post the most relevant code here.
So if you look it over, the program grabs the devices it can find on the network. Then it iterates through them looking for one with a MAC address it can use. If it does not find one it can use, it uses DEFAULT_MAC which is a constant defined elsewhere in the program as the array {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}.
Now it takes the current date and time in ticks and populates 8 bytes of the raw IV with that. Then it uses whichever MAC it found and uses it to fill more bytes in the same raw IV array.
Once that is done, it sends this raw array to the DigestRandomBytes method where, per the code (that code block is not included here) the method repeats a cycle 256 times of getting cryptographically secure random bytes, then hashes them using SHA-256. The one thing that concerns me -- only a little, granted -- is that I do not see how the MAC and datetime ticks bytes survive the DigestRandomBytes method or help increase the entropy of its output at all. They are sent into the DigestRandomBytes method, but it appears to discard them and replace them with random bytes, and it does this 256 times.
Anyway, though, yes, the IV1 is randomly generated.
private byte[] GenerateIv1()
{
byte[] iv = new byte[IV_SIZE];
long time = DateTime.Now.Ticks;
byte[] mac = null;
/**********************************************************************
* *
* NOTE: The time and mac are COMPONENTS in the random IV input. *
* The IV does not require the time or mac to be random. *
* *
* The mac and time are used to INCREASE the ENTROPY, and *
* DECOUPLE the IV from the PRNG output, in case the PRNG *
* has a defect (intentional or not) *
* *
* Please review the DigestRandomBytes method before *
* INCORRECTLY ASSUMING that the IV is generated from *
* time and mac inputs. *
* *
***********************************************************************/
try
{
System.Net.NetworkInformation.NetworkInterface[] interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
for (int i = 0; i < interfaces.Length; i++)
if (i != System.Net.NetworkInformation.NetworkInterface.LoopbackInterfaceIndex)
{
mac = interfaces[i].GetPhysicalAddress().GetAddressBytes();
break;
}
}
catch
{
//Not much to do, just go with default MAC
}
if (mac == null)
mac = DEFAULT_MAC;
for (int i = 0; i < 8; i++)
iv[i] = (byte)((time >> (i * 8)) & 0xff);
Array.Copy(mac, 0, iv, 8, Math.Min(mac.Length, iv.Length - 8));
return DigestRandomBytes(iv, 256);
}