Implement CFB with 8-bit mode
authorMathias L. Baumann <mathias.baumann_at_sociomantic.com>
Sat, 4 Feb 2017 11:30:41 +0000 (13:30 +0200)
committerJussi Kivilinna <jussi.kivilinna@iki.fi>
Sat, 4 Feb 2017 11:31:02 +0000 (13:31 +0200)
* cipher/cipher-cfb.c (_gcry_cipher_cfb8_encrypt)
(_gcry_cipher_cfg8_decrypt): Add 8-bit variants of decrypt/encrypt
functions.
* cipher/cipher-internal.h (_gcry_cipher_cfb8_encrypt)
(_gcry_cipher_cfg8_decrypt): Ditto.
* cipher/cipher.c: Adjust code flow to work with GCRY_CIPHER_MODE_CFB8.
* tests/basic.c: Add tests for cfb8 with AES and 3DES.
--

Signed-off-by: Mathias L. Baumann <mathias.baumann at sociomantic.com>
[JK: edit changelog, fix email malformed patch]
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
cipher/cipher-cfb.c
cipher/cipher-internal.h
cipher/cipher.c
tests/basic.c

index 21c81ca..cca5c1f 100644 (file)
@@ -233,3 +233,89 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c,
 
   return 0;
 }
+
+
+gcry_err_code_t
+_gcry_cipher_cfb8_encrypt (gcry_cipher_hd_t c,
+                          unsigned char *outbuf, size_t outbuflen,
+                          const unsigned char *inbuf, size_t inbuflen)
+{
+  gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
+  size_t blocksize = c->spec->blocksize;
+  unsigned int burn, nburn;
+
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+
+  burn = 0;
+
+  while ( inbuflen > 0)
+    {
+      /* Encrypt the IV. */
+      nburn = enc_fn ( &c->context.c, c->lastiv, c->u_iv.iv );
+      burn = nburn > burn ? nburn : burn;
+
+      outbuf[0] = c->lastiv[0] ^ inbuf[0];
+
+      /* Bitshift iv by 8 bit to the left */
+      for (int i = 0; i < blocksize-1; i++)
+        c->u_iv.iv[i] = c->u_iv.iv[i+1];
+
+      /* append cipher text to iv */
+      c->u_iv.iv[blocksize-1] = outbuf[0];
+
+      outbuf += 1;
+      inbuf += 1;
+      inbuflen -= 1;
+    }
+
+  if (burn > 0)
+    _gcry_burn_stack (burn + 4 * sizeof(void *));
+
+  return 0;
+}
+
+
+gcry_err_code_t
+_gcry_cipher_cfb8_decrypt (gcry_cipher_hd_t c,
+                          unsigned char *outbuf, size_t outbuflen,
+                          const unsigned char *inbuf, size_t inbuflen)
+{
+  gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
+  size_t blocksize = c->spec->blocksize;
+  unsigned int burn, nburn;
+  unsigned char appendee;
+
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+
+  burn = 0;
+
+  while (inbuflen > 0)
+    {
+      /* Encrypt the IV. */
+      nburn = enc_fn ( &c->context.c, c->lastiv, c->u_iv.iv );
+      burn = nburn > burn ? nburn : burn;
+
+      /* inbuf might == outbuf, make sure we keep the value
+         so we can append it later */
+      appendee = inbuf[0];
+
+      outbuf[0] = inbuf[0] ^ c->lastiv[0];
+
+      /* Bitshift iv by 8 bit to the left */
+      for (int i = 0; i < blocksize-1; i++)
+        c->u_iv.iv[i] = c->u_iv.iv[i+1];
+
+      c->u_iv.iv[blocksize-1] = appendee;
+
+      outbuf += 1;
+      inbuf += 1;
+      inbuflen -= 1;
+    }
+
+  if (burn > 0)
+    _gcry_burn_stack (burn + 4 * sizeof(void *));
+
+  return 0;
+}
index 33d0629..ea9c33d 100644 (file)
@@ -348,6 +348,14 @@ gcry_err_code_t _gcry_cipher_cfb_decrypt
 /*           */ (gcry_cipher_hd_t c,
                  unsigned char *outbuf, size_t outbuflen,
                  const unsigned char *inbuf, size_t inbuflen);
+gcry_err_code_t _gcry_cipher_cfb8_encrypt
+/*           */ (gcry_cipher_hd_t c,
+                 unsigned char *outbuf, size_t outbuflen,
+                 const unsigned char *inbuf, size_t inbuflen);
+gcry_err_code_t _gcry_cipher_cfb8_decrypt
+/*           */ (gcry_cipher_hd_t c,
+                 unsigned char *outbuf, size_t outbuflen,
+                 const unsigned char *inbuf, size_t inbuflen);
 
 
 /*-- cipher-ofb.c --*/
index 06ce1da..124700e 100644 (file)
@@ -415,6 +415,7 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
       case GCRY_CIPHER_MODE_ECB:
       case GCRY_CIPHER_MODE_CBC:
       case GCRY_CIPHER_MODE_CFB:
+      case GCRY_CIPHER_MODE_CFB8:
       case GCRY_CIPHER_MODE_OFB:
       case GCRY_CIPHER_MODE_CTR:
       case GCRY_CIPHER_MODE_AESWRAP:
@@ -902,6 +903,10 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
       rc = _gcry_cipher_cfb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
 
+    case GCRY_CIPHER_MODE_CFB8:
+      rc = _gcry_cipher_cfb8_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+      break;
+
     case GCRY_CIPHER_MODE_OFB:
       rc = _gcry_cipher_ofb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
@@ -1029,6 +1034,10 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
       rc = _gcry_cipher_cfb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
 
+    case GCRY_CIPHER_MODE_CFB8:
+      rc = _gcry_cipher_cfb8_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+      break;
+
     case GCRY_CIPHER_MODE_OFB:
       rc = _gcry_cipher_ofb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
index 6d086b5..1b61122 100644 (file)
@@ -893,7 +893,104 @@ check_cfb_cipher (void)
             16,
             "\x75\xa3\x85\x74\x1a\xb9\xce\xf8\x20\x31\x62\x3d\x55\xb1\xe4\x71" }
         }
-      }
+      },
+      { GCRY_CIPHER_AES, 1,
+       "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+       "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+       { { "\x6b",
+           1,
+           "\x3b"},
+         { "\xc1",
+           1,
+           "\x79"},
+         { "\xbe",
+           1,
+           "\x42"},
+         { "\xe2",
+           1,
+           "\x4c"},
+       }
+      },
+      { GCRY_CIPHER_AES192, 1,
+       "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
+       "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+       "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+       { { "\x6b",
+           1,
+           "\xcd"},
+         { "\xc1",
+           1,
+           "\xa2"},
+         { "\xbe",
+           1,
+           "\x52"},
+         { "\xe2",
+           1,
+           "\x1e"},
+        }
+      },
+      { GCRY_CIPHER_AES256, 1,
+       "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+       "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+       "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+       { { "\x6b",
+           1,
+           "\xdc"},
+         { "\xc1",
+           1,
+           "\x1f"},
+         { "\xbe",
+           1,
+           "\x1a"},
+         { "\xe2",
+           1,
+           "\x85"},
+        }
+      },
+      { GCRY_CIPHER_AES, 1,
+       "\x3a\x6f\x91\x59\x26\x3f\xa6\xce\xf2\xa0\x75\xca\xfa\xce\x58\x17",
+       "\x0f\xc2\x36\x62\xb7\xdb\xf7\x38\x27\xf0\xc7\xde\x32\x1c\xa3\x6e",
+       { { "\x87\xef\xeb\x8d\x55\x9e\xd3\x36\x77\x28",
+           10,
+           "\x8e\x9c\x50\x42\x56\x14\xd5\x40\xce\x11"},
+       }
+      },
+      { GCRY_CIPHER_AES192, 1,
+       "\x53\x7e\x7b\xf6\x61\xfd\x40\x24\xa0\x24\x61\x3f\x15\xb1\x36\x90"
+       "\xf7\xd0\xc8\x47\xc1\xe1\x89\x65",
+       "\x3a\x81\xf9\xd9\xd3\xc1\x55\xb0\xca\xad\x5d\x73\x34\x94\x76\xfc",
+       { { "\xd3\xd8\xb9\xb9\x84\xad\xc2\x42\x37\xee",
+           10,
+           "\x38\x79\xfe\xa7\x2a\xc9\x99\x29\xe5\x3a"},
+       }
+      },
+      { GCRY_CIPHER_AES256, 1,
+       "\xeb\xbb\x45\x66\xb5\xe1\x82\xe0\xf0\x72\x46\x6b\x0b\x31\x1d\xf3"
+       "\x8f\x91\x75\xbc\x02\x13\xa5\x53\x0b\xce\x2e\xc4\xd7\x4f\x40\x0d",
+       "\x09\x56\xa4\x8e\x01\x00\x2c\x9e\x16\x37\x6d\x6e\x30\x8d\xba\xd1",
+       { { "\xb0\xfe\x25\xac\x8d\x3d\x28\xa2\xf4\x71",
+           10,
+           "\x63\x8c\x68\x23\xe7\x25\x6f\xb5\x62\x6e"},
+       }
+      },
+      { GCRY_CIPHER_3DES, 1,
+       "\xe3\x34\x7a\x6b\x0b\xc1\x15\x2c\x64\x2a\x25\xcb\xd3\xbc\x31\xab"
+       "\xfb\xa1\x62\xa8\x1f\x19\x7c\x15",
+       "\xb7\x40\xcc\x21\xe9\x25\xe3\xc8",
+       { { "\xdb\xe9\x15\xfc\xb3\x3b\xca\x18\xef\x14",
+           10,
+           "\xf4\x80\x1a\x8d\x03\x9d\xb4\xca\x8f\xf6"},
+       }
+      },
+      { GCRY_CIPHER_3DES, 1,
+       "\x7c\xa2\x89\x38\xba\x6b\xec\x1f\xfe\xc7\x8f\x7c\xd6\x97\x61\x94"
+       "\x7c\xa2\x89\x38\xba\x6b\xec\x1f",
+       "\x95\x38\x96\x58\x6e\x49\xd3\x8f",
+       { { "\x2e\xa9\x56\xd4\xa2\x11\xdb\x68\x59\xb7",
+           10,
+           "\xf2\x0e\x53\x66\x74\xa6\x6f\xa7\x38\x05"},
+       }
+      },
     };
   gcry_cipher_hd_t hde, hdd;
   unsigned char out[MAX_DATA_LEN];
@@ -6179,6 +6276,7 @@ check_ciphers (void)
 
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_ECB, 0);
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_CFB, 0);
+      check_one_cipher (algos[i], GCRY_CIPHER_MODE_CFB8, 0);
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_OFB, 0);
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_CBC, 0);
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_CTS);