Skip to content

Commit 01e3fd0

Browse files
committed
Add support for CFB1 and CFB8
Signed-off-by: Steffen Jaeckel <[email protected]>
1 parent e028fae commit 01e3fd0

File tree

8 files changed

+281
-43
lines changed

8 files changed

+281
-43
lines changed

doc/crypt.tex

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ \subsection{Background}
799799
$P$ under the key $k$ as $E_k(P)$. In some modes there exists an initialization vector denoted as $C_{-1}$.
800800

801801
\subsubsection{ECB Mode}
802-
\index{ECB mode}
802+
\index{ECB Mode}
803803
ECB or Electronic Codebook Mode is the simplest method to use. It is given as:
804804
\begin{equation}
805805
C_i = E_k(P_i)
@@ -808,7 +808,7 @@ \subsubsection{ECB Mode}
808808
than once.
809809

810810
\subsubsection{CBC Mode}
811-
\index{CBC mode}
811+
\index{CBC Mode}
812812
CBC or Cipher Block Chaining mode is a simple mode designed to prevent trivial forms of replay and swap attacks on ciphers.
813813
It is given as:
814814
\begin{equation}
@@ -817,7 +817,7 @@ \subsubsection{CBC Mode}
817817
It is important that the initialization vector be unique and preferably random for each message encrypted under the same key.
818818

819819
\subsubsection{CTR Mode}
820-
\index{CTR mode}
820+
\index{CTR Mode}
821821
CTR or Counter Mode is a mode which only uses the encryption function of the cipher. Given a initialization vector which is
822822
treated as a large binary counter the CTR mode is given as:
823823
\begin{eqnarray}
@@ -829,24 +829,24 @@ \subsubsection{CTR Mode}
829829
as the block cipher is under a chosen plaintext attack (provided the initialization vector is unique).
830830

831831
\subsubsection{CFB Mode}
832-
\index{CFB mode}
832+
\index{CFB Mode}
833833
CFB or Ciphertext Feedback Mode is a mode akin to CBC. It is given as:
834834
\begin{eqnarray}
835835
C_i = P_i \oplus C_{-1} \nonumber \\
836836
C_{-1} = E_k(C_i)
837837
\end{eqnarray}
838-
Note that in this library the output feedback width is equal to the size of the block cipher. That is this mode is used
839-
to encrypt whole blocks at a time. However, the library will buffer data allowing the user to encrypt or decrypt partial
838+
The library supports all output feedback widths as specified in NIST SP 800-38A: CFB1, CFB8, and CFB64 resp. CFB128, i.e. equal
839+
to the size of the block cipher. The library will buffer data allowing the user to encrypt or decrypt partial
840840
blocks without a delay. When this mode is first setup it will initially encrypt the initialization vector as required.
841841

842842
\subsubsection{OFB Mode}
843-
\index{OFB mode}
843+
\index{OFB Mode}
844844
OFB or Output Feedback Mode is a mode akin to CBC as well. It is given as:
845845
\begin{eqnarray}
846846
C_{-1} = E_k(C_{-1}) \nonumber \\
847847
C_i = P_i \oplus C_{-1}
848848
\end{eqnarray}
849-
Like the CFB mode the output width in CFB mode is the same as the width of the block cipher. OFB mode will also
849+
The output width in OFB mode is the same as the width of the block cipher. OFB mode will also
850850
buffer the output which will allow you to encrypt or decrypt partial blocks without delay.
851851

852852
\subsection{Choice of Mode}
@@ -874,8 +874,8 @@ \subsection{Ciphertext Stealing}
874874
The more sane way to deal with partial blocks is to pad them with zeroes, and then use CBC normally.
875875

876876
\subsection{Initialization}
877-
\index{CBC Mode} \index{CTR Mode}
878-
\index{OFB Mode} \index{CFB Mode}
877+
\index{CBC Initialization} \index{CTR Initialization}
878+
\index{OFB Initialization} \index{CFB Initialization}
879879
The library provides simple support routines for handling CBC, CTR, CFB, OFB and ECB encoded messages. Assuming the mode
880880
you want is XXX there is a structure called \textit{symmetric\_XXX} that will contain the information required to
881881
use that mode. They have identical setup routines (except CTR and ECB mode):
@@ -913,6 +913,7 @@ \subsection{Initialization}
913913
The routines return {\bf CRYPT\_OK} if the cipher initialized correctly, otherwise, they return an error code.
914914

915915
\subsubsection{CTR Mode}
916+
\index{CTR Initialization - specific}
916917
In the case of CTR mode there is an additional parameter \textit{ctr\_mode} which specifies the mode that the counter is to be used in.
917918
If \textbf{CTR\_COUNTER\_ LITTLE\_ENDIAN} was specified then the counter will be treated as a little endian value. Otherwise, if
918919
\textbf{CTR\_COUNTER\_BIG\_ENDIAN} was specified the counter will be treated as a big endian value. As of v1.15 the RFC 3686 style of
@@ -942,6 +943,37 @@ \subsubsection{CTR Mode}
942943
Changing the counter size has little (really no) effect on the performance of the CTR chaining mode. It is provided for compatibility
943944
with other software (and hardware) which have smaller fixed sized counters.
944945

946+
\subsubsection{CFB Mode}
947+
\index{CFB Initialization - specific}
948+
949+
In the case of the CFB mode there are multiple segment sizes possible. The most common one, where each processed segment equals the
950+
block size of the underlying cipher, and two speciality modes. 1-bit CFB mode and 8-bit CFB mode, where each processed segment is
951+
either 1 or 8 bits wide. Each segment denotes here one block cipher operation.
952+
To produce 16 bytes AES-CFB output, a single AES operation is required.
953+
To produce 16 bytes AES-CFB8 output, 16 AES operations are required.
954+
To produce 16 bytes AES-CFB1 output, 128 AES operations are required.
955+
956+
The extended setup API looks as follows and accepts the values \textit{0, 1, 8 and 64 or 128}. Whether \textit{64} or \textit{128} is
957+
accepted depends on the block size of the underlying cipher, \textit{0} will automatically select the block size as width.
958+
959+
\begin{small}
960+
\begin{verbatim}
961+
/**
962+
Extended initialization of a CFB context
963+
@param cipher The index of the cipher desired
964+
@param IV The initialization vector
965+
@param key The secret key
966+
@param keylen The length of the secret key (octets)
967+
@param num_rounds Number of rounds in the cipher desired (0 for default)
968+
@param width The width of the mode (0 for default)
969+
@param cfb The CFB state to initialize
970+
@return CRYPT_OK if successful
971+
*/
972+
int cfb_start_ex(int cipher, const unsigned char *IV, const unsigned char *key,
973+
int keylen, int num_rounds, int width, symmetric_CFB *cfb);
974+
\end{verbatim}
975+
\end{small}
976+
945977
\subsection{Encryption and Decryption}
946978
To actually encrypt or decrypt the following routines are provided:
947979
\index{ecb\_encrypt()} \index{ecb\_decrypt()} \index{cfb\_encrypt()} \index{cfb\_decrypt()}

src/headers/tomcrypt_cipher.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ typedef struct {
275275
int cipher,
276276
/** The block size of the given cipher */
277277
blocklen,
278+
/** The width of the mode: 1, 8, 64, or 128 */
279+
width,
278280
/** The padding offset */
279281
padlen;
280282
} symmetric_CFB;
@@ -910,6 +912,8 @@ int ecb_done(symmetric_ECB *ecb);
910912
#ifdef LTC_CFB_MODE
911913
int cfb_start(int cipher, const unsigned char *IV, const unsigned char *key,
912914
int keylen, int num_rounds, symmetric_CFB *cfb);
915+
int cfb_start_ex(int cipher, const unsigned char *IV, const unsigned char *key,
916+
int keylen, int num_rounds, int width, symmetric_CFB *cfb);
913917
int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb);
914918
int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb);
915919
int cfb_getiv(unsigned char *IV, unsigned long *len, const symmetric_CFB *cfb);

src/modes/cfb/cfb_decrypt.c

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,28 @@
99

1010
#ifdef LTC_CFB_MODE
1111

12+
static LTC_INLINE void s_shift1left_64(unsigned char *b, unsigned char v)
13+
{
14+
ulong64 bval;
15+
LOAD64H(bval, b);
16+
bval <<= 1;
17+
bval |= v & 0x01u;
18+
STORE64H(bval, b);
19+
}
20+
21+
static LTC_INLINE void s_shift1left_128(unsigned char *b, unsigned char v)
22+
{
23+
ulong64 bval[2];
24+
LOAD64H(bval[0], b);
25+
LOAD64H(bval[1], b + 8);
26+
bval[0] <<= 1;
27+
bval[0] |= (bval[1] >> 63) & 0x01u;
28+
bval[1] <<= 1;
29+
bval[1] |= v & 0x01u;
30+
STORE64H(bval[0], b);
31+
STORE64H(bval[1], b + 8);
32+
}
33+
1234
/**
1335
CFB decrypt
1436
@param ct Ciphertext
@@ -20,11 +42,18 @@
2042
int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb)
2143
{
2244
int err;
45+
ulong64 bitlen = len * 8, bits_per_round;
46+
unsigned int cur_bit = 0;
47+
unsigned char pt_ = 0, ct_ = 0;
2348

2449
LTC_ARGCHK(pt != NULL);
2550
LTC_ARGCHK(ct != NULL);
2651
LTC_ARGCHK(cfb != NULL);
2752

53+
if (bitlen < len) {
54+
return CRYPT_OVERFLOW;
55+
}
56+
2857
if ((err = cipher_is_valid(cfb->cipher)) != CRYPT_OK) {
2958
return err;
3059
}
@@ -35,18 +64,51 @@ int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, s
3564
return CRYPT_INVALID_ARG;
3665
}
3766

38-
while (len-- > 0) {
67+
bits_per_round = cfb->width == 1 ? 1 : 8;
68+
69+
while (bitlen > 0) {
3970
if (cfb->padlen == cfb->blocklen) {
4071
if ((err = cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->pad, cfb->IV, &cfb->key)) != CRYPT_OK) {
4172
return err;
4273
}
4374
cfb->padlen = 0;
4475
}
45-
cfb->pad[cfb->padlen] = *ct;
46-
*pt = *ct ^ cfb->IV[cfb->padlen];
47-
++pt;
48-
++ct;
49-
++(cfb->padlen);
76+
switch (cfb->width) {
77+
case 1:
78+
if (cur_bit++ % 8 == 0) {
79+
ct_ = *ct++;
80+
pt_ = 0;
81+
} else {
82+
ct_ <<= 1;
83+
pt_ <<= 1;
84+
}
85+
if (cfb->blocklen == 16)
86+
s_shift1left_128(cfb->pad, ct_ >> 7);
87+
else
88+
s_shift1left_64(cfb->pad, ct_ >> 7);
89+
pt_ |= ((ct_ ^ cfb->IV[0]) >> 7) & 0x01u;
90+
cfb->padlen = cfb->blocklen;
91+
if (cur_bit % 8 == 0) {
92+
*pt++ = pt_;
93+
cur_bit = 0;
94+
}
95+
break;
96+
case 8:
97+
XMEMMOVE(cfb->pad, cfb->pad + 1, cfb->blocklen - 1);
98+
cfb->pad[cfb->blocklen - 1] = *ct;
99+
*pt++ = *ct++ ^ cfb->IV[0];
100+
cfb->padlen = cfb->blocklen;
101+
break;
102+
case 64:
103+
case 128:
104+
cfb->pad[cfb->padlen] = *ct;
105+
*pt++ = *ct++ ^ cfb->IV[cfb->padlen];
106+
++(cfb->padlen);
107+
break;
108+
default:
109+
return CRYPT_INVALID_ARG;
110+
}
111+
bitlen -= bits_per_round;
50112
}
51113
return CRYPT_OK;
52114
}

src/modes/cfb/cfb_encrypt.c

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,28 @@
99

1010
#ifdef LTC_CFB_MODE
1111

12+
static LTC_INLINE void s_shift1left_64(unsigned char *b, unsigned char v)
13+
{
14+
ulong64 bval;
15+
LOAD64H(bval, b);
16+
bval <<= 1;
17+
bval |= v & 0x01u;
18+
STORE64H(bval, b);
19+
}
20+
21+
static LTC_INLINE void s_shift1left_128(unsigned char *b, unsigned char v)
22+
{
23+
ulong64 bval[2];
24+
LOAD64H(bval[0], b);
25+
LOAD64H(bval[1], b + 8);
26+
bval[0] <<= 1;
27+
bval[0] |= (bval[1] >> 63) & 0x01u;
28+
bval[1] <<= 1;
29+
bval[1] |= v & 0x01u;
30+
STORE64H(bval[0], b);
31+
STORE64H(bval[1], b + 8);
32+
}
33+
1234
/**
1335
CFB encrypt
1436
@param pt Plaintext
@@ -20,11 +42,18 @@
2042
int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb)
2143
{
2244
int err;
45+
ulong64 bitlen = len * 8, bits_per_round;
46+
unsigned int cur_bit = 0;
47+
unsigned char pt_ = 0, ct_ = 0;
2348

2449
LTC_ARGCHK(pt != NULL);
2550
LTC_ARGCHK(ct != NULL);
2651
LTC_ARGCHK(cfb != NULL);
2752

53+
if (bitlen < len) {
54+
return CRYPT_OVERFLOW;
55+
}
56+
2857
if ((err = cipher_is_valid(cfb->cipher)) != CRYPT_OK) {
2958
return err;
3059
}
@@ -35,17 +64,51 @@ int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, s
3564
return CRYPT_INVALID_ARG;
3665
}
3766

38-
while (len-- > 0) {
39-
if (cfb->padlen == cfb->blocklen) {
40-
if ((err = cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->pad, cfb->IV, &cfb->key)) != CRYPT_OK) {
41-
return err;
42-
}
43-
cfb->padlen = 0;
44-
}
45-
cfb->pad[cfb->padlen] = (*ct = *pt ^ cfb->IV[cfb->padlen]);
46-
++pt;
47-
++ct;
48-
++(cfb->padlen);
67+
bits_per_round = cfb->width == 1 ? 1 : 8;
68+
69+
while (bitlen > 0) {
70+
if (cfb->padlen == cfb->blocklen) {
71+
if ((err = cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->pad, cfb->IV, &cfb->key)) != CRYPT_OK) {
72+
return err;
73+
}
74+
cfb->padlen = 0;
75+
}
76+
switch (cfb->width) {
77+
case 1:
78+
if (cur_bit++ % 8 == 0) {
79+
pt_ = *pt++;
80+
ct_ = 0;
81+
} else {
82+
pt_ <<= 1;
83+
ct_ <<= 1;
84+
}
85+
ct_ |= ((pt_ ^ cfb->IV[0]) >> 7) & 0x01u;
86+
if (cfb->blocklen == 16)
87+
s_shift1left_128(cfb->pad, ct_);
88+
else
89+
s_shift1left_64(cfb->pad, ct_);
90+
cfb->padlen = cfb->blocklen;
91+
if (cur_bit % 8 == 0) {
92+
*ct++ = ct_;
93+
cur_bit = 0;
94+
}
95+
break;
96+
case 8:
97+
XMEMMOVE(cfb->pad, cfb->pad + 1, cfb->blocklen - 1);
98+
cfb->pad[cfb->blocklen - 1] = (*ct = *pt ^ cfb->IV[0]);
99+
++pt;
100+
++ct;
101+
cfb->padlen = cfb->blocklen;
102+
break;
103+
case 64:
104+
case 128:
105+
cfb->pad[cfb->padlen] = (*ct = *pt ^ cfb->IV[cfb->padlen]);
106+
++pt;
107+
++ct;
108+
++(cfb->padlen);
109+
break;
110+
}
111+
bitlen -= bits_per_round;
49112
}
50113
return CRYPT_OK;
51114
}

src/modes/cfb/cfb_getiv.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ int cfb_getiv(unsigned char *IV, unsigned long *len, const symmetric_CFB *cfb)
2525
*len = cfb->blocklen;
2626
return CRYPT_BUFFER_OVERFLOW;
2727
}
28-
XMEMCPY(IV, cfb->IV, cfb->blocklen);
28+
XMEMCPY(IV, cfb->pad, cfb->blocklen);
2929
*len = cfb->blocklen;
3030

3131
return CRYPT_OK;

src/modes/cfb/cfb_setiv.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ int cfb_setiv(const unsigned char *IV, unsigned long len, symmetric_CFB *cfb)
3333

3434
/* force next block */
3535
cfb->padlen = 0;
36+
XMEMCPY(cfb->pad, IV, len);
3637
return cipher_descriptor[cfb->cipher].ecb_encrypt(IV, cfb->IV, &cfb->key);
3738
}
3839

0 commit comments

Comments
 (0)