Commit 58e54b2f authored by Dmitry Baryshkov's avatar Dmitry Baryshkov Committed by Niels Möller
Browse files

Add CFB8 - Cipher Feedback 8-bit block cipher mode



Add CFB variant with 8-bit segment size.
Signed-off-by: Dmitry Baryshkov's avatarDmitry Eremin-Solenikov <dbaryshkov@gmail.com>
parent c4a814d7
...@@ -162,3 +162,75 @@ cfb_decrypt(const void *ctx, nettle_cipher_func *f, ...@@ -162,3 +162,75 @@ cfb_decrypt(const void *ctx, nettle_cipher_func *f,
} }
} }
} }
/* CFB-8 uses slight optimization: it encrypts or decrypts up to block_size
* bytes and does memcpy/memxor afterwards */
void
cfb8_encrypt(const void *ctx, nettle_cipher_func *f,
size_t block_size, uint8_t *iv,
size_t length, uint8_t *dst,
const uint8_t *src)
{
TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE * 2);
TMP_DECL(outbuf, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE);
TMP_ALLOC(buffer, block_size * 2);
TMP_ALLOC(outbuf, block_size);
uint8_t pos;
memcpy(buffer, iv, block_size);
pos = 0;
while (length)
{
uint8_t t;
if (pos == block_size)
{
memcpy(buffer, buffer + block_size, block_size);
pos = 0;
}
f(ctx, block_size, outbuf, buffer + pos);
t = *(dst++) = *(src++) ^ outbuf[0];
buffer[pos + block_size] = t;
length--;
pos ++;
}
memcpy(iv, buffer + pos, block_size);
}
void
cfb8_decrypt(const void *ctx, nettle_cipher_func *f,
size_t block_size, uint8_t *iv,
size_t length, uint8_t *dst,
const uint8_t *src)
{
TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE * 2);
TMP_DECL(outbuf, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE * 2);
TMP_ALLOC(buffer, block_size * 2);
TMP_ALLOC(outbuf, block_size * 2);
uint8_t i = 0;
memcpy(buffer, iv, block_size);
memcpy(buffer + block_size, src,
length < block_size ? length : block_size);
while (length)
{
for (i = 0; i < length && i < block_size; i++)
f(ctx, block_size, outbuf + i, buffer + i);
memxor3(dst, src, outbuf, i);
length -= i;
src += i;
dst += i;
memcpy(buffer, buffer + block_size, block_size);
memcpy(buffer + block_size, src,
length < block_size ? length : block_size);
}
memcpy(iv, buffer + i, block_size);
}
...@@ -45,6 +45,9 @@ extern "C" { ...@@ -45,6 +45,9 @@ extern "C" {
#define cfb_encrypt nettle_cfb_encrypt #define cfb_encrypt nettle_cfb_encrypt
#define cfb_decrypt nettle_cfb_decrypt #define cfb_decrypt nettle_cfb_decrypt
#define cfb8_encrypt nettle_cfb8_encrypt
#define cfb8_decrypt nettle_cfb8_decrypt
void void
cfb_encrypt(const void *ctx, nettle_cipher_func *f, cfb_encrypt(const void *ctx, nettle_cipher_func *f,
size_t block_size, uint8_t *iv, size_t block_size, uint8_t *iv,
...@@ -57,12 +60,28 @@ cfb_decrypt(const void *ctx, nettle_cipher_func *f, ...@@ -57,12 +60,28 @@ cfb_decrypt(const void *ctx, nettle_cipher_func *f,
size_t length, uint8_t *dst, size_t length, uint8_t *dst,
const uint8_t *src); const uint8_t *src);
void
cfb8_encrypt(const void *ctx, nettle_cipher_func *f,
size_t block_size, uint8_t *iv,
size_t length, uint8_t *dst,
const uint8_t *src);
void
cfb8_decrypt(const void *ctx, nettle_cipher_func *f,
size_t block_size, uint8_t *iv,
size_t length, uint8_t *dst,
const uint8_t *src);
#define CFB_CTX(type, size) \ #define CFB_CTX(type, size) \
{ type ctx; uint8_t iv[size]; } { type ctx; uint8_t iv[size]; }
#define CFB_SET_IV(ctx, data) \ #define CFB_SET_IV(ctx, data) \
memcpy((ctx)->iv, (data), sizeof((ctx)->iv)) memcpy((ctx)->iv, (data), sizeof((ctx)->iv))
#define CFB8_CTX CFB_CTX
#define CFB8_SET_IV CFB_SET_IV
/* NOTE: Avoid using NULL, as we don't include anything defining it. */ /* NOTE: Avoid using NULL, as we don't include anything defining it. */
#define CFB_ENCRYPT(self, f, length, dst, src) \ #define CFB_ENCRYPT(self, f, length, dst, src) \
(0 ? ((f)(&(self)->ctx, ~(size_t) 0, \ (0 ? ((f)(&(self)->ctx, ~(size_t) 0, \
...@@ -80,6 +99,22 @@ memcpy((ctx)->iv, (data), sizeof((ctx)->iv)) ...@@ -80,6 +99,22 @@ memcpy((ctx)->iv, (data), sizeof((ctx)->iv))
sizeof((self)->iv), (self)->iv, \ sizeof((self)->iv), (self)->iv, \
(length), (dst), (src))) (length), (dst), (src)))
#define CFB8_ENCRYPT(self, f, length, dst, src) \
(0 ? ((f)(&(self)->ctx, ~(size_t) 0, \
(uint8_t *) 0, (const uint8_t *) 0)) \
: cfb8_encrypt((void *) &(self)->ctx, \
(nettle_cipher_func *) (f), \
sizeof((self)->iv), (self)->iv, \
(length), (dst), (src)))
#define CFB8_DECRYPT(self, f, length, dst, src) \
(0 ? ((f)(&(self)->ctx, ~(size_t) 0, \
(uint8_t *) 0, (const uint8_t *) 0)) \
: cfb8_decrypt((void *) &(self)->ctx, \
(nettle_cipher_func *) (f), \
sizeof((self)->iv), (self)->iv, \
(length), (dst), (src)))
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
......
...@@ -93,7 +93,7 @@ Cipher modes ...@@ -93,7 +93,7 @@ Cipher modes
* CBC:: * CBC::
* CTR:: * CTR::
* CFB:: * CFB and CFB8::
* GCM:: * GCM::
* CCM:: * CCM::
...@@ -1904,21 +1904,21 @@ Book mode, @acronym{ECB}), leaks information. ...@@ -1904,21 +1904,21 @@ Book mode, @acronym{ECB}), leaks information.
Besides @acronym{ECB}, Nettle provides several other modes of operation: Besides @acronym{ECB}, Nettle provides several other modes of operation:
Cipher Block Chaining (@acronym{CBC}), Counter mode (@acronym{CTR}), Cipher Cipher Block Chaining (@acronym{CBC}), Counter mode (@acronym{CTR}), Cipher
Feedback (@acronym{CFB}) and a couple of @acronym{AEAD} modes Feedback (@acronym{CFB} and @acronym{CFB8}) and a couple of @acronym{AEAD}
(@pxref{Authenticated encryption}). @acronym{CBC} is widely used, but modes (@pxref{Authenticated encryption}). @acronym{CBC} is widely used, but
there are a few subtle issues of information leakage, see, e.g., there are a few subtle issues of information leakage, see, e.g.,
@uref{http://www.kb.cert.org/vuls/id/958563, @acronym{SSH} @acronym{CBC} @uref{http://www.kb.cert.org/vuls/id/958563, @acronym{SSH} @acronym{CBC}
vulnerability}. Today, @acronym{CTR} is usually preferred over @acronym{CBC}. vulnerability}. Today, @acronym{CTR} is usually preferred over @acronym{CBC}.
Modes like @acronym{CBC}, @acronym{CTR} and @acronym{CFB} provide @emph{no} Modes like @acronym{CBC}, @acronym{CTR}, @acronym{CFB} and @acronym{CFB8}
message authentication, and should always be used together with a provide @emph{no} message authentication, and should always be used together
@acronym{MAC} (@pxref{Keyed hash functions}) or signature to authenticate with a @acronym{MAC} (@pxref{Keyed hash functions}) or signature to
the message. authenticate the message.
@menu @menu
* CBC:: * CBC::
* CTR:: * CTR::
* CFB:: * CFB and CFB8::
@end menu @end menu
@node CBC, CTR, Cipher modes, Cipher modes @node CBC, CTR, Cipher modes, Cipher modes
...@@ -2014,7 +2014,7 @@ These macros use some tricks to make the compiler display a warning if ...@@ -2014,7 +2014,7 @@ These macros use some tricks to make the compiler display a warning if
the types of @var{f} and @var{ctx} don't match, e.g. if you try to use the types of @var{f} and @var{ctx} don't match, e.g. if you try to use
an @code{struct aes_ctx} context with the @code{des_encrypt} function. an @code{struct aes_ctx} context with the @code{des_encrypt} function.
@node CTR, CFB, CBC, Cipher modes @node CTR, CFB and CFB8, CBC, Cipher modes
@comment node-name, next, previous, up @comment node-name, next, previous, up
@subsection Counter mode @subsection Counter mode
...@@ -2090,18 +2090,21 @@ last three arguments define the source and destination area for the ...@@ -2090,18 +2090,21 @@ last three arguments define the source and destination area for the
operation. operation.
@end deffn @end deffn
@node CFB, , CTR, Cipher modes @node CFB and CFB8, , CTR, Cipher modes
@comment node-name, next, previous, up @comment node-name, next, previous, up
@subsection Cipher Feedback mode @subsection Cipher Feedback mode
@cindex Cipher Feedback Mode @cindex Cipher Feedback Mode
@cindex CFB Mode @cindex Cipher Feedback 8-bit Mode
@cindex CFB Modes
@cindex CFB8 Mode
Cipher Feedback mode (@acronym{CFB}) being a close relative to both
@acronym{CBC} mode and @acronym{CTR} mode borrows some characteristics
from stream ciphers.
The message is divided into @code{n} blocks @code{M_1},@dots{} Cipher Feedback mode (@acronym{CFB}) and Cipher Feedback 8-bit mode
(@acronym{CFB8}) being close relatives to both @acronym{CBC} mode and
@acronym{CTR} mode borrow some characteristics from stream ciphers.
For CFB the message is divided into @code{n} blocks @code{M_1},@dots{}
@code{M_n}, where @code{M_n} is of size @code{m} which may be smaller @code{M_n}, where @code{M_n} is of size @code{m} which may be smaller
than the block size. Except for the last block, all the message blocks than the block size. Except for the last block, all the message blocks
must be of size equal to the cipher's block size. must be of size equal to the cipher's block size.
...@@ -2121,10 +2124,31 @@ C_(n-1) = E_k(C_(n - 2)) XOR M_(n-1) ...@@ -2121,10 +2124,31 @@ C_(n-1) = E_k(C_(n - 2)) XOR M_(n-1)
C_n = E_k(C_(n - 1)) [1..m] XOR M_n C_n = E_k(C_(n - 1)) [1..m] XOR M_n
@end example @end example
Nettle's includes two functions for applying a block cipher in Cipher Cipher Feedback 8-bit mode (@acronym{CFB8}) transforms block cipher into a stream
Feedback (@acronym{CFB}) mode, one for encryption and one for cipher. The message is encrypted byte after byte, not requiring any padding.
decryption. These functions uses @code{void *} to pass cipher contexts
around. If @code{E_k} is the encryption function of a block cipher, @code{b} is
@code{E_k} block size, @code{IV} is the initialization vector, then the
@code{n} plaintext bytes are transformed into @code{n} ciphertext bytes
@code{C_1},@dots{} @code{C_n} as follows:
@example
I_1 = IV
C_1 = E_k(I_1) [1..8] XOR M_1
I_2 = I_1 [9..b] << 8 | C_1
C_2 = E_k(I_2) [1..8] XOR M_2
@dots{}
I_(n-1) = I_(n-2) [9..b] << 8 | C_(n-2)
C_(n-1) = E_k(I_(n-1)) [1..8] XOR M_(n-1)
I_n = I_(n-1) [9..b] << 8 | C_(n-1)
C_n = E_k(I_n) [1..8] XOR M_n
@end example
Nettle's includes functions for applying a block cipher in Cipher
Feedback (@acronym{CFB}) and Cipher Feedback 8-bit (@acronym{CFB8})
modes. These functions uses @code{void *} to pass cipher contexts around.
@deftypefun {void} cfb_encrypt (const void *@var{ctx}, nettle_cipher_func *@var{f}, size_t @var{block_size}, uint8_t *@var{iv}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src}) @deftypefun {void} cfb_encrypt (const void *@var{ctx}, nettle_cipher_func *@var{f}, size_t @var{block_size}, uint8_t *@var{iv}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src})
@deftypefunx {void} cfb_decrypt (const void *@var{ctx}, nettle_cipher_func *@var{f}, size_t @var{block_size}, uint8_t *@var{iv}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src}) @deftypefunx {void} cfb_decrypt (const void *@var{ctx}, nettle_cipher_func *@var{f}, size_t @var{block_size}, uint8_t *@var{iv}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src})
...@@ -2141,6 +2165,18 @@ When a message is encrypted using a sequence of calls to ...@@ -2141,6 +2165,18 @@ When a message is encrypted using a sequence of calls to
is a multiple of the block size. is a multiple of the block size.
@end deftypefun @end deftypefun
@deftypefun {void} cfb8_encrypt (const void *@var{ctx}, nettle_cipher_func *@var{f}, size_t @var{block_size}, uint8_t *@var{iv}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src})
@deftypefunx {void} cfb8_decrypt (const void *@var{ctx}, nettle_cipher_func *@var{f}, size_t @var{block_size}, uint8_t *@var{iv}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src})
Applies the encryption or decryption function @var{f} in @acronym{CFB8}
mode. The final IV block processed is copied into @var{iv}
before returning, so that a large message can be processed by a sequence of
calls to @code{cfb8_encrypt}. Note that for @acronym{CFB8} mode internally
uses encryption only function and hence @var{f} should always be the
encryption function for the underlying block cipher.
@end deftypefun
Like for @acronym{CBC}, there are also a couple of helper macros. Like for @acronym{CBC}, there are also a couple of helper macros.
@deffn Macro CFB_CTX (@var{context_type}, @var{block_size}) @deffn Macro CFB_CTX (@var{context_type}, @var{block_size})
...@@ -2175,6 +2211,38 @@ last three arguments define the source and destination area for the ...@@ -2175,6 +2211,38 @@ last three arguments define the source and destination area for the
operation. operation.
@end deffn @end deffn
@deffn Macro CFB8_CTX (@var{context_type}, @var{block_size})
Expands to
@example
@{
context_type ctx;
uint8_t iv[block_size];
@}
@end example
@end deffn
@deffn Macro CFB8_SET_IV(@var{ctx}, @var{iv})
First argument is a pointer to a context struct as defined by
@code{CFB8_CTX}, and the second is a pointer to an initialization vector
that is copied into that context.
@end deffn
@deffn Macro CFB8_ENCRYPT (@var{ctx}, @var{f}, @var{length}, @var{dst}, @var{src})
A simpler way to invoke @code{cfb8_encrypt}. The first argument is a
pointer to a context struct as defined by @code{CFB8_CTX}, and the
second argument is an encryption function following Nettle's
conventions. The last three arguments define the source and destination
area for the operation.
@end deffn
@deffn Macro CFB8_DECRYPT (@var{ctx}, @var{f}, @var{length}, @var{dst}, @var{src})
A simpler way to invoke @code{cfb8_decrypt}. The first argument is a
pointer to a context struct as defined by @code{CFB8_CTX}, and the
second argument is an encryption function following Nettle's
conventions. The last three arguments define the source and destination
area for the operation.
@end deffn
@node Authenticated encryption, Keyed hash functions, Cipher modes, Reference @node Authenticated encryption, Keyed hash functions, Cipher modes, Reference
@comment node-name, next, previous, up @comment node-name, next, previous, up
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
/* Test with more data and inplace decryption, to check that the /* Test with more data and inplace decryption, to check that the
* cfb_decrypt buffering works. */ * cfb_decrypt buffering works. */
#define CFB_BULK_DATA 10000 #define CFB_BULK_DATA 10000
#define CFB8_BULK_DATA CFB_BULK_DATA
static void static void
test_cfb_bulk(void) test_cfb_bulk(void)
...@@ -64,9 +65,110 @@ test_cfb_bulk(void) ...@@ -64,9 +65,110 @@ test_cfb_bulk(void)
ASSERT (MEMEQ(CFB_BULK_DATA, clear, cipher)); ASSERT (MEMEQ(CFB_BULK_DATA, clear, cipher));
} }
static void
test_cfb8_bulk(void)
{
struct knuth_lfib_ctx random;
uint8_t clear[CFB8_BULK_DATA];
uint8_t cipher[CFB8_BULK_DATA + 1];
const uint8_t *key = H("966c7bf00bebe6dc 8abd37912384958a"
"743008105a08657d dcaad4128eee38b3");
const uint8_t *start_iv = H("11adbff119749103 207619cfa0e8d13a");
const uint8_t *end_iv = H("f84bfd48206f5803 6ef86f4e69e9aec0");
struct CFB8_CTX(struct aes_ctx, AES_BLOCK_SIZE) aes;
knuth_lfib_init(&random, CFB8_BULK_DATA);
knuth_lfib_random(&random, CFB8_BULK_DATA, clear);
/* Byte that should not be overwritten */
cipher[CFB8_BULK_DATA] = 17;
aes_set_encrypt_key(&aes.ctx, 32, key);
CFB8_SET_IV(&aes, start_iv);
CFB8_ENCRYPT(&aes, aes_encrypt, CFB8_BULK_DATA, cipher, clear);
ASSERT(cipher[CFB8_BULK_DATA] == 17);
if (verbose)
{
printf("IV after bulk encryption: ");
print_hex(AES_BLOCK_SIZE, aes.iv);
printf("\n");
}
ASSERT(MEMEQ(AES_BLOCK_SIZE, aes.iv, end_iv));
/* Decrypt, in place */
aes_set_encrypt_key(&aes.ctx, 32, key);
CFB8_SET_IV(&aes, start_iv);
CFB8_DECRYPT(&aes, aes_encrypt, CFB8_BULK_DATA, cipher, cipher);
ASSERT(cipher[CFB8_BULK_DATA] == 17);
if (verbose)
{
printf("IV after bulk decryption: ");
print_hex(AES_BLOCK_SIZE, aes.iv);
printf("\n");
}
ASSERT (MEMEQ(AES_BLOCK_SIZE, aes.iv, end_iv));
ASSERT (MEMEQ(CFB8_BULK_DATA, clear, cipher));
}
void void
test_main(void) test_main(void)
{ {
/* From NIST spec 800-38a on AES modes.
*
* F.3 CFB Example Vectors
* F.3.7 CFB8-AES128.Encrypt
*/
test_cipher_cfb8(&nettle_aes128,
SHEX("2b7e151628aed2a6abf7158809cf4f3c"),
SHEX("6bc1bee22e409f96e93d7e117393172a"
"ae2d"),
SHEX("3b79424c9c0dd436bace9e0ed4586a4f"
"32b9"),
SHEX("000102030405060708090a0b0c0d0e0f"));
/* From NIST spec 800-38a on AES modes.
*
* F.3 CFB Example Vectors
* F.3.9 CFB8-AES192.Encrypt
*/
test_cipher_cfb8(&nettle_aes192,
SHEX("8e73b0f7da0e6452c810f32b809079e5"
"62f8ead2522c6b7b"),
SHEX("6bc1bee22e409f96e93d7e117393172a"
"ae2d"),
SHEX("cda2521ef0a905ca44cd057cbf0d47a0"
"678a"),
SHEX("000102030405060708090a0b0c0d0e0f"));
/* From NIST spec 800-38a on AES modes.
*
* F.3 CFB Example Vectors
* F.3.11 CFB8-AES256.Encrypt
*/
test_cipher_cfb8(&nettle_aes256,
SHEX("603deb1015ca71be2b73aef0857d7781"
"1f352c073b6108d72d9810a30914dff4"),
SHEX("6bc1bee22e409f96e93d7e117393172a"
"ae2d"),
SHEX("dc1f1a8520a64db55fcc8ac554844e88"
"9700"),
SHEX("000102030405060708090a0b0c0d0e0f"));
/* From NIST spec 800-38a on AES modes. /* From NIST spec 800-38a on AES modes.
* *
* F.3 CFB Example Vectors * F.3 CFB Example Vectors
...@@ -139,6 +241,7 @@ test_main(void) ...@@ -139,6 +241,7 @@ test_main(void)
SHEX("000102030405060708090a0b0c0d0e0f")); SHEX("000102030405060708090a0b0c0d0e0f"));
test_cfb_bulk(); test_cfb_bulk();
test_cfb8_bulk();
} }
/* /*
......
...@@ -423,6 +423,184 @@ test_cipher_cfb(const struct nettle_cipher *cipher, ...@@ -423,6 +423,184 @@ test_cipher_cfb(const struct nettle_cipher *cipher,
free(iv); free(iv);
} }
void
test_cipher_cfb8(const struct nettle_cipher *cipher,
const struct tstring *key,
const struct tstring *cleartext,
const struct tstring *ciphertext,
const struct tstring *iiv)
{
void *ctx = xalloc(cipher->context_size);
uint8_t *data, *data2;
uint8_t *iv = xalloc(cipher->block_size);
size_t length;
ASSERT (cleartext->length == ciphertext->length);
length = cleartext->length;
ASSERT (key->length == cipher->key_size);
ASSERT (iiv->length == cipher->block_size);
data = xalloc(length);
data2 = xalloc(length);
cipher->set_encrypt_key(ctx, key->data);
memcpy(iv, iiv->data, cipher->block_size);
cfb8_encrypt(ctx, cipher->encrypt,
cipher->block_size, iv,
length, data, cleartext->data);
if (!MEMEQ(length, data, ciphertext->data))
{
fprintf(stderr, "CFB8 encrypt failed:\nInput:");
tstring_print_hex(cleartext);
fprintf(stderr, "\nOutput: ");
print_hex(length, data);
fprintf(stderr, "\nExpected:");
tstring_print_hex(ciphertext);
fprintf(stderr, "\n");
FAIL();
}
cipher->set_encrypt_key(ctx, key->data);
memcpy(iv, iiv->data, cipher->block_size);
cfb8_decrypt(ctx, cipher->encrypt,
cipher->block_size, iv,
length, data2, data);
if (!MEMEQ(length, data2, cleartext->data))
{
fprintf(stderr, "CFB8 decrypt failed:\nInput:");
tstring_print_hex(ciphertext);
fprintf(stderr, "\nOutput: ");
print_hex(length, data2);
fprintf(stderr, "\nExpected:");
tstring_print_hex(cleartext);
fprintf(stderr, "\n");
FAIL();
}
cipher->set_encrypt_key(ctx, key->data);
memcpy(iv, iiv->data, cipher->block_size);
memcpy(data, cleartext->data, length);
cfb8_encrypt(ctx, cipher->encrypt,
cipher->block_size, iv,
length, data, data);
if (!MEMEQ(length, data, ciphertext->data))
{
fprintf(stderr, "CFB8 inplace encrypt failed:\nInput:");
tstring_print_hex(cleartext);
fprintf(stderr, "\nOutput: ");
print_hex(length, data);
fprintf(stderr, "\nExpected:");
tstring_print_hex(ciphertext);
fprintf(stderr, "\n");
FAIL();
}
cipher->set_encrypt_key(ctx, key->data);
memcpy(iv, iiv->data, cipher->block_size);
cfb8_decrypt(ctx, cipher->encrypt,
cipher->block_size, iv,
length, data, data);
if (!MEMEQ(length, data, cleartext->data))
{
fprintf(stderr, "CFB8 inplace decrypt failed:\nInput:");
tstring_print_hex(ciphertext);
fprintf(stderr, "\nOutput: ");
print_hex(length, data);
fprintf(stderr, "\nExpected:");
tstring_print_hex(cleartext);
fprintf(stderr, "\n");
FAIL();
}
/* Repeat all tests with incomplete last block */
length -= 1;
cipher->set_encrypt_key(ctx, key->data);
memcpy(iv, iiv->data, cipher->block_size);
cfb8_encrypt(ctx, cipher->encrypt,
cipher->block_size, iv,
length, data, cleartext->data);
if (!MEMEQ(length, data, ciphertext->data))
{
fprintf(stderr, "CFB8 encrypt failed:\nInput:");
print_hex(length, cleartext->data);
fprintf(stderr, "\nOutput: ");
print_hex(length, data);
fprintf(stderr, "\nExpected:");
print_hex(length, ciphertext->data);
fprintf(stderr, "\n");
FAIL();
}
cipher->set_encrypt_key(ctx, key->data);
memcpy(iv, iiv->data, cipher->block_size);
cfb8_decrypt(ctx, cipher->encrypt,
cipher->block_size, iv,
length, data2, data);