This code is supposed to implement RFC 3394 which also described in this PDF at page 11.
Are there any weak places or formatting issues in attached source? Or maybe some places are not explicit enough?
void wrap( const unsigned char *key, const unsigned char *plaintext, unsigned int plaintext_length,
unsigned char *ciphertext, unsigned int *ciphertext_length, unsigned int semiblocksize)
{
int i, j, k;
unsigned int n, t, tt;
unsigned char *A, B[16], *R;
int targetlevel = 0, p = semiblocksize;
while (p >>= 1) ++targetlevel;
n = plaintext_length >> targetlevel;
A = B;
memset(A, 0xa6, semiblocksize);
memcpy(ciphertext+semiblocksize, plaintext, plaintext_length);
for(j=0, t=1; j<=5; j++)
{
for(i=1, R=ciphertext+semiblocksize; i<=n; i++, t++, R+=semiblocksize)
{
memcpy(B+semiblocksize, R, semiblocksize);
AES128_ECB_encrypt(B, key, B);
for(k=semiblocksize - 1, tt=t; (k>=0) && (tt>0); k--, tt>>=semiblocksize)
{
A[k] ^= (unsigned char) (tt & 0xFF);
}
memcpy(R, B+semiblocksize, semiblocksize);
}
}
memcpy(ciphertext, A, semiblocksize);
*ciphertext_length = plaintext_length + semiblocksize;
}
I know, that ECB mode should not be used in production, but this is only for ensuring output correctness by checking coincidence with the RFC.
1 Answer 1
Arrays are best indexed with type
size_t
rather thanunsigned
. Notice unnecessary mixedint/unsigned
types ini<=n
. Both should besize_t
.Avoid naked magic numbers. Why
16
inunsigned char B[16]
?Formatting: For review purposes, consider limiting to the width to the target display.
// void wrap( const unsigned char *key, const unsigned char *plaintext, unsigned int plaintext_length, // unsigned char *ciphertext, unsigned int *ciphertext_length, unsigned int semiblocksize) void wrap(const unsigned char *key, const unsigned char *plaintext, unsigned int plaintext_length, unsigned char *ciphertext, unsigned int *ciphertext_length, unsigned int semiblocksize)
See little value in the vertical line spacing. Removing a few of these blank line to group common elements together would make more sense.
unsigned char *A, B[16], *R; int targetlevel = 0, p = semiblocksize; while (p >>= 1) ++targetlevel; n = plaintext_length >> targetlevel; A = B; memset(A, 0xa6, semiblocksize); memcpy(ciphertext+semiblocksize, plaintext, plaintext_length); for(j=0, t=1; j<=5; j++)
for()
loops are best coded withfor (i=first_value; i<some_N; i += delta)
. Complex usage offor()
loops tend to be code golfing. Indexing from0
is idiomatic in C and should be followed when reasonable. Following this helps convey meaning and avoids off-by-1 errors.// for(j=0, t=1; j<=5; j++) { // for(i=1, R=ciphertext+semiblocksize; i<=n; i++, t++, R+=semiblocksize) t = 0; for(j=0; j<6; j++) { R = ciphertext; for(i=0; i<n; i++) { R += semiblocksize; t++; ... } }
Variable names
A
,B
convey little meaning unless standard for the encryption algorithm's notation.Cast serves no purpose here in C
// A[k] ^= (unsigned char) (tt & 0xFF); A[k] ^= tt & 0xFF;