// Recover the key from CBC with IV=Key
#include "aes.h"
#include "random.h"
/*
* take your code from the cbc exercise and modify so that it repurposes the key
* for cbc encryption as the iv. applications sometimes use the key as an iv on
* the auspices that both the sender and the receiver have to know the key
* already, and can save some space by using it as both a key and an iv. using
* the key as an iv is insecure; an attacker can modify ciphertext in flight can
* get the receiver to decrypt a value that will reveal the key. the cbc code
* from exercise 16 encrypts a url string. verify each byte of the plaintext for
* ascii compliacne (ie. look for high-ascii values). noncompliant messages
* should raise an exception or return an error that includes the decrypted
* plaintext (this happens all the time in real systems, for what it's worth).
* use your code to encrypt a message that is at least 3 blocks long:
* 'aes_cbc(p1, p2, p3) -> c1, c2, c3'. modify the message (you are now the
* attacker): 'c1, c2, c3 -> c1, 0, c1'. decrypt the message (you are now the
* receiver) and raise the appropriate error if high-ascii is found. as the
* attacker, recovering the plaintext from the error, extract the key: 'p1 ^
* p3'.
*/
unsigned char *key;
unsigned char *iv;
struct bytes validate(struct bytes input) {
struct bytes decrypted = aes_decrypt_cbc(input.data, input.len, key, 16, iv);
if (!decrypted.data || !decrypted.len)
return (struct bytes){NULL, 0};
return decrypted;
}
int main(void) {
srand(time(NULL));
key = iv = (unsigned char *)"ITSNOTCOMINGHOME";
while (true) {
unsigned char *rand_data = random_bytes(16);
unsigned char attack_blocks[48];
struct bytes payload = {attack_blocks, sizeof(attack_blocks)};
memcpy(attack_blocks, rand_data, AES_BLOCK_SIZE);
memset(attack_blocks + AES_BLOCK_SIZE, 0, AES_BLOCK_SIZE);
memcpy(attack_blocks + AES_BLOCK_SIZE * 2, rand_data, AES_BLOCK_SIZE);
struct bytes valid = validate(payload);
if (!valid.data) {
free(rand_data);
continue;
}
if (valid.len < AES_BLOCK_SIZE * 3) {
free(valid.data);
free(rand_data);
continue;
}
unsigned char recovered_key[17] = {0};
for (size_t i = 0; i < AES_BLOCK_SIZE; i++)
recovered_key[i] = valid.data[i] ^ valid.data[i + AES_BLOCK_SIZE * 2];
printf("Recovered key: ");
for (size_t i = 0; i < 16; i++)
printf("%c", recovered_key[i]);
printf("\n");
free(valid.data);
free(rand_data);
break;
}
return 0;
}