I think there's a bug in the AES counter mode implementation: if you pass a
non-zero counter offset to AES_ctr128_encrypt() (through the "num" argument),
this function will access unitialized data in "tmp".
I'm not sure if this function is intended to provide stream-like services, but
if it is, then I have test code which demonstrates the bug and a patch that
fixes it. I have included both below.
The test code encrypts both halves of a message with separate calls to
AES_ctr128_encrypt() and then decrypts the whole message with a single call.
When the two halves of the message are compared with the decrypted message,
we see that something went wrong. The problem is as mentioned above: the
second call to AES_ctr128_encrypt() has a non-zero counter offset. This
causes the function to xor part of the second half of the message with
garbage (i.e. unitialized data in "tmp").
The patch fixes this problem by initializing "tmp" if the counter offset is
non-zero. The patch also changes the increment of the counter in the main
loop so that it is only incremented if we have at least a full block of data
remaining.
Matt
#include <stdio.h>
#include <string.h>
#include <openssl/aes.h>
#define KEY_LENGTH 16
#define TEXT_LENGTH 36
#define COUNTER_LENGTH 16
int main(void)
{
unsigned char key[KEY_LENGTH + 1] = "9dfe5ea4c3f84ae3";
unsigned char plaintext1[(TEXT_LENGTH / 2) + 1] = "123456789012345678";
unsigned char plaintext2[(TEXT_LENGTH / 2) + 1] = "876543210987654321";
unsigned char ciphertext[TEXT_LENGTH + 1];
unsigned char plaintext[TEXT_LENGTH + 1];
unsigned char ecounter[COUNTER_LENGTH + 1] = "6543210987654321";
unsigned char dcounter[COUNTER_LENGTH + 1] = "6543210987654321";
AES_KEY k;
int num;
int retval;
retval = AES_set_encrypt_key(key, strlen(key) * 8, &k);
if (retval < 0) {
printf("couldn't set encrypt key: %d\n", retval);
return -1;
}
num = 0;
AES_ctr128_encrypt(plaintext1, ciphertext, strlen(plaintext1),
&k, ecounter, &num);
AES_ctr128_encrypt(plaintext2, ciphertext + strlen(plaintext1),
strlen(plaintext2), &k, ecounter, &num);
num = 0;
AES_ctr128_encrypt(ciphertext, plaintext,
strlen(plaintext1) + strlen(plaintext2),
&k, dcounter, &num);
retval = strncmp(plaintext, plaintext1, strlen(plaintext1));
if (retval != 0) {
printf("error\n");
return -1;
}
retval = strncmp(plaintext + strlen(plaintext1), plaintext2,
strlen(plaintext2));
if (retval != 0) {
printf("error\n");
return -1;
}
printf("success\n");
return 0;
}
--- openssl-0.9.7-beta2.orig/crypto/aes/aes_ctr.c Thu May 30 07:06:17 2002
+++ openssl-0.9.7-beta2/crypto/aes/aes_ctr.c Mon Jul 29 15:01:05 2002
@@ -103,11 +103,18 @@
assert(in && out && key && counter && num);
n = *num;
+ assert(n < AES_BLOCK_SIZE);
+
+ if (n) {
+ AES_encrypt(counter, tmp, key);
+ AES_ctr128_inc(counter);
+ }
while (l--) {
if (n == 0) {
AES_encrypt(counter, tmp, key);
- AES_ctr128_inc(counter);
+ if (l >= AES_BLOCK_SIZE - 1)
+ AES_ctr128_inc(counter);
}
*(out++) = *(in++) ^ tmp[n];
n = (n+1) % AES_BLOCK_SIZE;
______________________________________________________________________
OpenSSL Project http://www.openssl.org
Development Mailing List [EMAIL PROTECTED]
Automated List Manager [EMAIL PROTECTED]