i believe i have found a bug in BF_cbc_encrypt() in 0.9.5a.
still not sure if it was repaired in 0.9.6beta2, i hope to test
this with 0.9.6beta2 sooner (if you can, please).
from cbc definition:
P1 P2 Pi
| | |
IV->->(X) +>->->->(X) +>->->->(X)
v ^ v ^ v
+-----+ ^ +-----+ ^ +-----+
k1->| E | ^ k1->| E | ^ k1->| E |
+-----+ ^ +-----+ ^ +-----+
v ^ v ^ v
+>->->+ +>->->+ +>->->
| | |
C1 C2 Ci
if IV is all zero, C1 must be equal to ciphertext generated by
simple single block cipher, like
C1 == encrypt(P1, k1)
but this is not the case for openssl BF_cbc_encrypt.
the attached code emits the result like this:
>itojun[lychee:~] ./a.out
>enc 0: 0
>enc 1: 0
>enc 2: 0
>dec 0: 0
>dec 1: 0
>dec 2: 0
>src(ossl cbc): 655f58083e07d1d2
>dst(ossl cbc): 2f939dbe9aeff6ca <--- this has to be 4ac41f9e488b2a3f
>src(test cbc): 655f58083e07d1d2
>dst(test cbc): 4ac41f9e488b2a3f
is my impression correct? if so, i'll try to repair BF_cbc_encrypt.
itojun
#include <sys/types.h>
#include <stdio.h>
#include <openssl/blowfish.h>
u_int8_t enc[][8] = {
{ 0x65, 0x5f, 0x58, 0x08, 0x3e, 0x07, 0xd1, 0xd2, },
{ 0x4a, 0xc4, 0x1f, 0x9e, 0x48, 0x8b, 0x2a, 0x3f, },
{ 0x73, 0x02, 0x28, 0xa2, 0x48, 0x86, 0xbe, 0xfe, },
{ 0xcc, 0x9c, 0x67, 0xad, 0x59, 0x1b, 0x99, 0x64, },
{ 0xc8, 0x9f, 0x65, 0xac, 0x63, 0x1d, 0x9f, 0x61, },
{ 0x9a, 0x34, 0x24, 0x0c, 0xeb, 0xf0, 0x25, 0x09, },
};
u_int8_t dec[][8] = {
{ 0x4a, 0xc4, 0x1f, 0x9e, 0x48, 0x8b, 0x2a, 0x3f, },
{ 0x65, 0x5f, 0x58, 0x08, 0x3e, 0x07, 0xd1, 0xd2, },
{ 0xcc, 0x9c, 0x67, 0xad, 0x59, 0x1b, 0x99, 0x64, },
{ 0x73, 0x02, 0x28, 0xa2, 0x48, 0x86, 0xbe, 0xfe, },
{ 0x9a, 0x34, 0x24, 0x0c, 0xeb, 0xf0, 0x25, 0x09, },
{ 0xc8, 0x9f, 0x65, 0xac, 0x63, 0x1d, 0x9f, 0x61, },
};
int bf_cbc_encrypt __P((u_int8_t *, u_int8_t *, size_t, BF_KEY *, u_int8_t *));
int
dump8(title, p)
char *title;
u_int8_t *p;
{
int i;
printf("%s: ", title);
for (i = 0; i < 8; i++)
printf("%02x", p[i]);
printf("\n");
}
int
main()
{
BF_KEY k;
int i;
u_int8_t d[8];
u_int8_t ivec[8];
u_int8_t scbc[24];
u_int8_t dcbc[24];
BF_set_key(&k, 8, "hogehoge");
for (i = 0; i < 3; i++) {
memcpy(d, enc[i * 2], 8);
BF_encrypt((BF_LONG *)d, &k);
printf("enc %d: %d\n", i, memcmp(d, enc[i * 2 + 1], 8));
}
for (i = 0; i < 3; i++) {
memcpy(d, dec[i * 2], 8);
BF_decrypt((BF_LONG *)d, &k);
printf("dec %d: %d\n", i, memcmp(d, dec[i * 2 + 1], 8));
}
memcpy(&scbc[0], enc[0], 8);
memcpy(&scbc[8], enc[2], 8);
memcpy(&scbc[16], enc[4], 8);
memset(ivec, 0, sizeof(ivec));
BF_cbc_encrypt(scbc, dcbc, 24, &k, ivec, BF_ENCRYPT);
dump8("src(ossl cbc)", scbc);
dump8("dst(ossl cbc)", dcbc);
memset(ivec, 0, sizeof(ivec));
bf_cbc_encrypt(scbc, dcbc, 24, &k, ivec);
dump8("src(test cbc)", scbc);
dump8("dst(test cbc)", dcbc);
}
/* home brew CBC code */
int
bf_cbc_encrypt(s, d, l, k, iv)
u_int8_t *s;
u_int8_t *d;
size_t l;
BF_KEY *k;
u_int8_t *iv;
{
size_t off;
u_int8_t b[8];
int i;
u_int8_t *ivp;
ivp = iv;
for (off = 0; off < l; off += 8) {
memcpy(d + off, s + off, 8);
for (i = 0; i < 8; i++)
d[off + i] ^= ivp[i];
BF_encrypt(&d[off], k);
ivp = &d[off];
}
return 0;
}