Fix CFB and OFB modes in eng_padlock.c. Engine was consistent with itself,
but not interoperable with the rest of the world. test_padlock script is added mostly for reference.
This commit is contained in:
parent
7a5dbeb782
commit
34b537ee66
@ -257,7 +257,9 @@ struct padlock_cipher_data
|
|||||||
union { unsigned int pad[4];
|
union { unsigned int pad[4];
|
||||||
struct {
|
struct {
|
||||||
int rounds:4;
|
int rounds:4;
|
||||||
int algo:3;
|
int dgst:1; /* n/a in C3 */
|
||||||
|
int align:1; /* n/a in C3 */
|
||||||
|
int ciphr:1; /* n/a in C3 */
|
||||||
int keygen:1;
|
int keygen:1;
|
||||||
int interm:1;
|
int interm:1;
|
||||||
int encdec:1;
|
int encdec:1;
|
||||||
@ -650,17 +652,13 @@ static int padlock_cipher_nids[] = {
|
|||||||
|
|
||||||
NID_aes_192_ecb,
|
NID_aes_192_ecb,
|
||||||
NID_aes_192_cbc,
|
NID_aes_192_cbc,
|
||||||
#if 0
|
NID_aes_192_cfb,
|
||||||
NID_aes_192_cfb, /* FIXME: AES192/256 CFB/OFB don't work. */
|
|
||||||
NID_aes_192_ofb,
|
NID_aes_192_ofb,
|
||||||
#endif
|
|
||||||
|
|
||||||
NID_aes_256_ecb,
|
NID_aes_256_ecb,
|
||||||
NID_aes_256_cbc,
|
NID_aes_256_cbc,
|
||||||
#if 0
|
|
||||||
NID_aes_256_cfb,
|
NID_aes_256_cfb,
|
||||||
NID_aes_256_ofb,
|
NID_aes_256_ofb,
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
static int padlock_cipher_nids_num = (sizeof(padlock_cipher_nids)/
|
static int padlock_cipher_nids_num = (sizeof(padlock_cipher_nids)/
|
||||||
sizeof(padlock_cipher_nids[0]));
|
sizeof(padlock_cipher_nids[0]));
|
||||||
@ -676,12 +674,17 @@ static int padlock_aes_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
|||||||
#define ALIGNED_CIPHER_DATA(ctx) ((struct padlock_cipher_data *)\
|
#define ALIGNED_CIPHER_DATA(ctx) ((struct padlock_cipher_data *)\
|
||||||
NEAREST_ALIGNED(ctx->cipher_data))
|
NEAREST_ALIGNED(ctx->cipher_data))
|
||||||
|
|
||||||
|
#define EVP_CIPHER_block_size_ECB AES_BLOCK_SIZE
|
||||||
|
#define EVP_CIPHER_block_size_CBC AES_BLOCK_SIZE
|
||||||
|
#define EVP_CIPHER_block_size_OFB 1
|
||||||
|
#define EVP_CIPHER_block_size_CFB 1
|
||||||
|
|
||||||
/* Declaring so many ciphers by hand would be a pain.
|
/* Declaring so many ciphers by hand would be a pain.
|
||||||
Instead introduce a bit of preprocessor magic :-) */
|
Instead introduce a bit of preprocessor magic :-) */
|
||||||
#define DECLARE_AES_EVP(ksize,lmode,umode) \
|
#define DECLARE_AES_EVP(ksize,lmode,umode) \
|
||||||
static const EVP_CIPHER padlock_aes_##ksize##_##lmode = { \
|
static const EVP_CIPHER padlock_aes_##ksize##_##lmode = { \
|
||||||
NID_aes_##ksize##_##lmode, \
|
NID_aes_##ksize##_##lmode, \
|
||||||
AES_BLOCK_SIZE, \
|
EVP_CIPHER_block_size_##umode, \
|
||||||
AES_KEY_SIZE_##ksize, \
|
AES_KEY_SIZE_##ksize, \
|
||||||
AES_BLOCK_SIZE, \
|
AES_BLOCK_SIZE, \
|
||||||
0 | EVP_CIPH_##umode##_MODE, \
|
0 | EVP_CIPH_##umode##_MODE, \
|
||||||
@ -783,7 +786,10 @@ padlock_aes_init_key (EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
|||||||
memset(cdata, 0, sizeof(struct padlock_cipher_data));
|
memset(cdata, 0, sizeof(struct padlock_cipher_data));
|
||||||
|
|
||||||
/* Prepare Control word. */
|
/* Prepare Control word. */
|
||||||
cdata->cword.b.encdec = (ctx->encrypt == 0);
|
if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_OFB_MODE)
|
||||||
|
cdata->cword.b.encdec = 0;
|
||||||
|
else
|
||||||
|
cdata->cword.b.encdec = (ctx->encrypt == 0);
|
||||||
cdata->cword.b.rounds = 10 + (key_len - 128) / 32;
|
cdata->cword.b.rounds = 10 + (key_len - 128) / 32;
|
||||||
cdata->cword.b.ksize = (key_len - 128) / 64;
|
cdata->cword.b.ksize = (key_len - 128) / 64;
|
||||||
|
|
||||||
@ -803,7 +809,9 @@ padlock_aes_init_key (EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
|||||||
and is listed as hardware errata. They most
|
and is listed as hardware errata. They most
|
||||||
likely will fix it at some point and then
|
likely will fix it at some point and then
|
||||||
a check for stepping would be due here. */
|
a check for stepping would be due here. */
|
||||||
if (enc)
|
if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CFB_MODE ||
|
||||||
|
EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_OFB_MODE ||
|
||||||
|
enc)
|
||||||
AES_set_encrypt_key(key, key_len, &cdata->ks);
|
AES_set_encrypt_key(key, key_len, &cdata->ks);
|
||||||
else
|
else
|
||||||
AES_set_decrypt_key(key, key_len, &cdata->ks);
|
AES_set_decrypt_key(key, key_len, &cdata->ks);
|
||||||
@ -897,10 +905,53 @@ padlock_aes_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
|
|||||||
int inp_misaligned, out_misaligned, realign_in_loop;
|
int inp_misaligned, out_misaligned, realign_in_loop;
|
||||||
size_t chunk, allocated=0;
|
size_t chunk, allocated=0;
|
||||||
|
|
||||||
|
/* ctx->num is maintained in byte-oriented modes,
|
||||||
|
such as CFB and OFB... */
|
||||||
|
if ((chunk = ctx->num)) { /* borrow chunk variable */
|
||||||
|
unsigned char *ivp=ctx->iv;
|
||||||
|
|
||||||
|
switch (EVP_CIPHER_CTX_mode(ctx)) {
|
||||||
|
case EVP_CIPH_CFB_MODE:
|
||||||
|
if (chunk >= AES_BLOCK_SIZE)
|
||||||
|
return 0; /* bogus value */
|
||||||
|
|
||||||
|
if (ctx->encrypt)
|
||||||
|
while (chunk<AES_BLOCK_SIZE && nbytes!=0) {
|
||||||
|
ivp[chunk] = *(out_arg++) = *(in_arg++) ^ ivp[chunk];
|
||||||
|
chunk++, nbytes--;
|
||||||
|
}
|
||||||
|
else while (chunk<AES_BLOCK_SIZE && nbytes!=0) {
|
||||||
|
unsigned char c = *(in_arg++);
|
||||||
|
*(out_arg++) = c ^ ivp[chunk];
|
||||||
|
ivp[chunk++] = c, nbytes--;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->num = chunk%AES_BLOCK_SIZE;
|
||||||
|
break;
|
||||||
|
case EVP_CIPH_OFB_MODE:
|
||||||
|
if (chunk >= AES_BLOCK_SIZE)
|
||||||
|
return 0; /* bogus value */
|
||||||
|
|
||||||
|
while (chunk<AES_BLOCK_SIZE && nbytes!=0) {
|
||||||
|
*(out_arg++) = *(in_arg++) ^ ivp[chunk];
|
||||||
|
chunk++, nbytes--;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->num = chunk%AES_BLOCK_SIZE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
#if 0
|
||||||
if (nbytes % AES_BLOCK_SIZE)
|
if (nbytes % AES_BLOCK_SIZE)
|
||||||
return 0; /* are we expected to do tail processing? */
|
return 0; /* are we expected to do tail processing? */
|
||||||
|
#else
|
||||||
|
/* nbytes is always multiple of AES_BLOCK_SIZE in ECB and CBC
|
||||||
|
modes and arbitrary value in byte-oriented modes, such as
|
||||||
|
CFB and OFB... */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* VIA promises CPUs that won't require alignment in the future.
|
/* VIA promises CPUs that won't require alignment in the future.
|
||||||
For now padlock_aes_align_required is initialized to 1 and
|
For now padlock_aes_align_required is initialized to 1 and
|
||||||
@ -910,7 +961,7 @@ padlock_aes_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
|
|||||||
same as for software alignment below or ~3x. They promise to
|
same as for software alignment below or ~3x. They promise to
|
||||||
improve it in the future, but for now we can just as well
|
improve it in the future, but for now we can just as well
|
||||||
pretend that it can only handle aligned input... */
|
pretend that it can only handle aligned input... */
|
||||||
if (!padlock_aes_align_required)
|
if (!padlock_aes_align_required && (nbytes%AES_BLOCK_SIZE)==0)
|
||||||
return padlock_aes_cipher_omnivorous(ctx, out_arg, in_arg, nbytes);
|
return padlock_aes_cipher_omnivorous(ctx, out_arg, in_arg, nbytes);
|
||||||
|
|
||||||
inp_misaligned = (((size_t)in_arg) & 0x0F);
|
inp_misaligned = (((size_t)in_arg) & 0x0F);
|
||||||
@ -922,7 +973,7 @@ padlock_aes_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
|
|||||||
* in order to improve L1 cache utilization... */
|
* in order to improve L1 cache utilization... */
|
||||||
realign_in_loop = out_misaligned|inp_misaligned;
|
realign_in_loop = out_misaligned|inp_misaligned;
|
||||||
|
|
||||||
if (!realign_in_loop)
|
if (!realign_in_loop && (nbytes%AES_BLOCK_SIZE)==0)
|
||||||
return padlock_aes_cipher_omnivorous(ctx, out_arg, in_arg, nbytes);
|
return padlock_aes_cipher_omnivorous(ctx, out_arg, in_arg, nbytes);
|
||||||
|
|
||||||
/* this takes one "if" out of the loops */
|
/* this takes one "if" out of the loops */
|
||||||
@ -989,8 +1040,10 @@ padlock_aes_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EVP_CIPH_CFB_MODE:
|
case EVP_CIPH_CFB_MODE:
|
||||||
memcpy (cdata->iv, ctx->iv, AES_BLOCK_SIZE);
|
memcpy (iv = cdata->iv, ctx->iv, AES_BLOCK_SIZE);
|
||||||
goto cfb_shortcut;
|
chunk &= ~(AES_BLOCK_SIZE-1);
|
||||||
|
if (chunk) goto cfb_shortcut;
|
||||||
|
else goto cfb_skiploop;
|
||||||
do {
|
do {
|
||||||
if (iv != cdata->iv)
|
if (iv != cdata->iv)
|
||||||
memcpy(cdata->iv, iv, AES_BLOCK_SIZE);
|
memcpy(cdata->iv, iv, AES_BLOCK_SIZE);
|
||||||
@ -1009,13 +1062,47 @@ padlock_aes_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
|
|||||||
else
|
else
|
||||||
out = out_arg+=chunk;
|
out = out_arg+=chunk;
|
||||||
|
|
||||||
} while (nbytes -= chunk);
|
nbytes -= chunk;
|
||||||
|
} while (nbytes >= AES_BLOCK_SIZE);
|
||||||
|
|
||||||
|
cfb_skiploop:
|
||||||
|
if (nbytes) {
|
||||||
|
unsigned char *ivp = cdata->iv;
|
||||||
|
|
||||||
|
if (iv != ivp) {
|
||||||
|
memcpy(ivp, iv, AES_BLOCK_SIZE);
|
||||||
|
iv = ivp;
|
||||||
|
}
|
||||||
|
ctx->num = nbytes;
|
||||||
|
if (cdata->cword.b.encdec) {
|
||||||
|
cdata->cword.b.encdec=0;
|
||||||
|
padlock_reload_key();
|
||||||
|
padlock_xcrypt_ecb(1,cdata,ivp,ivp);
|
||||||
|
cdata->cword.b.encdec=1;
|
||||||
|
padlock_reload_key();
|
||||||
|
while(nbytes) {
|
||||||
|
unsigned char c = *(in_arg++);
|
||||||
|
*(out_arg++) = c ^ *ivp;
|
||||||
|
*(ivp++) = c, nbytes--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { padlock_reload_key();
|
||||||
|
padlock_xcrypt_ecb(1,cdata,ivp,ivp);
|
||||||
|
padlock_reload_key();
|
||||||
|
while (nbytes) {
|
||||||
|
*ivp = *(out_arg++) = *(in_arg++) ^ *ivp;
|
||||||
|
ivp++, nbytes--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
|
memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVP_CIPH_OFB_MODE:
|
case EVP_CIPH_OFB_MODE:
|
||||||
memcpy(cdata->iv, ctx->iv, AES_BLOCK_SIZE);
|
memcpy(cdata->iv, ctx->iv, AES_BLOCK_SIZE);
|
||||||
do {
|
chunk &= ~(AES_BLOCK_SIZE-1);
|
||||||
|
if (chunk) do {
|
||||||
if (inp_misaligned)
|
if (inp_misaligned)
|
||||||
inp = padlock_memcpy(out, in_arg, chunk);
|
inp = padlock_memcpy(out, in_arg, chunk);
|
||||||
else
|
else
|
||||||
@ -1031,7 +1118,21 @@ padlock_aes_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
|
|||||||
|
|
||||||
nbytes -= chunk;
|
nbytes -= chunk;
|
||||||
chunk = PADLOCK_CHUNK;
|
chunk = PADLOCK_CHUNK;
|
||||||
} while (nbytes);
|
} while (nbytes >= AES_BLOCK_SIZE);
|
||||||
|
|
||||||
|
if (nbytes) {
|
||||||
|
unsigned char *ivp = cdata->iv;
|
||||||
|
|
||||||
|
ctx->num = nbytes;
|
||||||
|
padlock_reload_key(); /* empirically found */
|
||||||
|
padlock_xcrypt_ecb(1,cdata,ivp,ivp);
|
||||||
|
padlock_reload_key(); /* empirically found */
|
||||||
|
while (nbytes) {
|
||||||
|
*(out_arg++) = *(in_arg++) ^ *ivp;
|
||||||
|
ivp++, nbytes--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(ctx->iv, cdata->iv, AES_BLOCK_SIZE);
|
memcpy(ctx->iv, cdata->iv, AES_BLOCK_SIZE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
64
test/test_padlock
Executable file
64
test/test_padlock
Executable file
@ -0,0 +1,64 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
PROG=$1
|
||||||
|
|
||||||
|
if [ -x $PROG ]; then
|
||||||
|
if expr "x`$PROG version`" : "xOpenSSL" > /dev/null; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
echo "$PROG is not OpenSSL executable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "$PROG is not executable"
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $PROG engine padlock | grep -v no-ACE; then
|
||||||
|
|
||||||
|
HASH=`cat $PROG | $PROG dgst -hex`
|
||||||
|
|
||||||
|
ACE_ALGS=" aes-128-ecb aes-192-ecb aes-256-ecb \
|
||||||
|
aes-128-cbc aes-192-cbc aes-256-cbc \
|
||||||
|
aes-128-cfb aes-192-cfb aes-256-cfb \
|
||||||
|
aes-128-ofb aes-192-ofb aes-256-ofb"
|
||||||
|
|
||||||
|
nerr=0
|
||||||
|
|
||||||
|
for alg in $ACE_ALGS; do
|
||||||
|
echo $alg
|
||||||
|
TEST=`( cat $PROG | \
|
||||||
|
$PROG enc -e -k $HASH -$alg -bufsize 999 -engine padlock | \
|
||||||
|
$PROG enc -d -k $HASH -$alg | \
|
||||||
|
$PROG dgst -hex ) 2>/dev/null`
|
||||||
|
if [ $TEST != $HASH ]; then
|
||||||
|
echo "-$alg encrypt test failed"
|
||||||
|
nerr=`expr $nerr + 1`
|
||||||
|
fi
|
||||||
|
TEST=`( cat $PROG | \
|
||||||
|
$PROG enc -e -k $HASH -$alg | \
|
||||||
|
$PROG enc -d -k $HASH -$alg -bufsize 999 -engine padlock | \
|
||||||
|
$PROG dgst -hex ) 2>/dev/null`
|
||||||
|
if [ $TEST != $HASH ]; then
|
||||||
|
echo "-$alg decrypt test failed"
|
||||||
|
nerr=`expr $nerr + 1`
|
||||||
|
fi
|
||||||
|
TEST=`( cat $PROG | \
|
||||||
|
$PROG enc -e -k $HASH -$alg -engine padlock | \
|
||||||
|
$PROG enc -d -k $HASH -$alg -engine padlock | \
|
||||||
|
$PROG dgst -hex ) 2>/dev/null`
|
||||||
|
if [ $TEST != $HASH ]; then
|
||||||
|
echo "-$alg en/decrypt test failed"
|
||||||
|
nerr=`expr $nerr + 1`
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $nerr -gt 0 ]; then
|
||||||
|
echo "PadLock ACE test failed."
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "PadLock ACE is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
Loading…
Reference in New Issue
Block a user