Переглянути джерело

Merge pull request #343 from libtom/feature/pkcs7

Add padding/depadding support
Steffen Jaeckel 7 роки тому
батько
коміт
e299431be8

+ 12 - 41
demos/openssl-enc.c

@@ -172,50 +172,21 @@ void dump_bytes(unsigned char *in, unsigned long len)
  * Output:       number of bytes after padding resp. after unpadding
  * Side Effects: none
  */
-size_t pkcs7_pad(union paddable *buf, size_t nb, int block_length,
+static size_t _pkcs7_pad(union paddable *buf, size_t nb, int block_length,
                  int is_padding)
 {
-   unsigned char padval;
-   off_t idx;
+   unsigned long length;
 
    if(is_padding) {
-      /* We are PADDING this block (and therefore adding bytes) */
-      /* The pad value in PKCS#7 is the number of bytes remaining in
-         the block, so for a 16-byte block and 3 bytes left, it's
-         0x030303.  In the oddball case where nb is an exact multiple
-         multiple of block_length, set the padval to blocksize (i.e.
-         add one full block) */
-      padval = (unsigned char) (block_length - (nb % block_length));
-      padval = padval ? padval : block_length;
-
-      memset(buf->pad+nb, padval, padval);
-      return nb+padval;
+      length = sizeof(buf->pad);
+      if (padding_pad(buf->pad, nb, &length, block_length) != CRYPT_OK)
+         return 0;
+      return length;
    } else {
-      /* We are UNPADDING this block (and removing bytes)
-         We really just need to verify that the pad bytes are correct,
-         so start at the end of the string and work backwards. */
-
-      /* Figure out what the padlength should be by looking at the
-         last byte */
-      idx = nb-1;
-      padval = buf->pad[idx];
-
-      /* padval must be nonzero and <= block length */
-      if(padval <= 0 || padval > block_length)
+      length = nb;
+      if (padding_depad(buf->pad, &length, 0) != CRYPT_OK)
          return 0;
-
-      /* First byte's accounted for; do the rest */
-      idx--;
-
-      while(idx >= (off_t)(nb-padval))
-         if(buf->pad[idx] != padval)
-            return 0;
-         else
-            idx--;
-
-      /* If we got here, the pad checked out, so return a smaller
-         number of bytes than nb (basically where we left off+1) */
-      return idx+1;
+      return length;
    }
 }
 
@@ -259,7 +230,7 @@ int do_crypt(FILE *infd, FILE *outfd, unsigned char *key, unsigned char *iv,
          /* We're encrypting, so pad first (if at EOF) and then
             crypt */
          if(feof(infd))
-            nb = pkcs7_pad(&inbuf, nb,
+            nb = _pkcs7_pad(&inbuf, nb,
                            aes_desc.block_length, 1);
 
          ret = cbc_encrypt(inbuf.pad, outbuf.pad, nb, &cbc);
@@ -273,8 +244,8 @@ int do_crypt(FILE *infd, FILE *outfd, unsigned char *key, unsigned char *iv,
          if( ret != CRYPT_OK )
             return ret;
 
-         if( feof(infd) )
-            nb = pkcs7_pad(&outbuf, nb,
+         if(feof(infd))
+            nb = _pkcs7_pad(&outbuf, nb,
                            aes_desc.block_length, 0);
          if(nb == 0)
             /* The file didn't decrypt correctly */

+ 66 - 0
doc/crypt.tex

@@ -6650,6 +6650,72 @@ int base16_decode(const          char *in,
                         unsigned char *out, unsigned long *outlen);
 \end{verbatim}
 
+\mysection{Padding data}
+
+The library provides functions to pad and depad according to several standards, please refer to Figure \ref{fig:paddingmodes} for details about the supported standards.
+
+
+\subsection{Padding mode argument}
+
+All functions have a \textit{mode} argument which must be set to the bit-wise OR of the desired blocksize and one of the modes as shown in the following table:
+
+\begin{figure}[H]
+\begin{minipage}{\textwidth}
+\begin{center}
+\begin{tabular}{|l|l|}
+     \hline \textbf{mode} & \textbf{Standard} \\
+     \hline LTC\_PAD\_PKCS7  & RFC-5652 / PKCS \#7 \\
+     \hline LTC\_PAD\_ISO\_10126 & ISO/IEC 10126 \footnote{\textit{ISO/IEC 10126} support is only available when the library is built with \textit{rng\_get\_bytes()} support} \\
+     \hline LTC\_PAD\_ANSI\_X923 & ANSI X.923 \\
+     \hline LTC\_PAD\_ONE\_AND\_ZERO & ISO/IEC 7816-4 \\
+     \hline LTC\_PAD\_ZERO & ISO/IEC 10118-1 \\
+     \hline LTC\_PAD\_ZERO\_ALWAYS & ISO/IEC 10118-1 \footnote{\textit{LTC\_PAD\_ZERO\_ALWAYS} adds an entire block of padding if the plaintext length is divisible by the blocksize} \\
+     \hline
+\end{tabular}
+\end{center}
+\end{minipage}
+\caption{Padding modes}
+\label{fig:paddingmodes}
+\end{figure}
+
+\textit{ISO/IEC 10126} has been withdrawn as an ISO/IEC standard in 2007 and is only provided for historical reasons (it was used e.g. in early versions of TLS/SSL).
+Therefore it should not be used for new designs.
+
+
+\subsection{Padding}
+
+To pad data call:
+
+\index{padding\_pad()}
+\begin{verbatim}
+int padding_pad(unsigned char *data,
+                unsigned long  length,
+                unsigned long *padded_length,
+                unsigned long  mode);
+\end{verbatim}
+
+Where \textit{data} is a pointer to a buffer containing the data to pad,
+\textit{length} is the original length of the data to pad and
+\textit{padded\_length} is a pointer that should contain the length of buffer available and will contain the padded data-length.
+It is possible to call this function with \textit{padded\_length} set to $0$ which will then return with the error-code \textit{CRYPT\_BUFFER\_OVERFLOW}
+and \textit{padded\_length} set to the required size of the buffer.
+
+
+\subsection{Depadding}
+
+To depad data call:
+
+\index{padding\_depad()}
+\begin{verbatim}
+int pkcs7_depad(unsigned char *data,
+                unsigned long *length,
+                unsigned long  mode);
+\end{verbatim}
+
+Where \textit{data} is a pointer to the data to depad,
+\textit{length} is a pointer that should contain the length of the padded data and will be updated to contain the length of the data after depadding.
+
+
 \mysection{Primality Testing}
 \index{Primality Testing}
 The library includes primality testing and random prime functions as well.  The primality tester will perform the test in

+ 12 - 0
libtomcrypt_VS2008.vcproj

@@ -1551,6 +1551,18 @@
 					>
 				</File>
 			</Filter>
+			<Filter
+				Name="padding"
+				>
+				<File
+					RelativePath="src\misc\padding\padding_depad.c"
+					>
+				</File>
+				<File
+					RelativePath="src\misc\padding\padding_pad.c"
+					>
+				</File>
+			</Filter>
 			<Filter
 				Name="pkcs5"
 				>

+ 3 - 2
makefile.mingw

@@ -109,7 +109,8 @@ src/misc/crypt/crypt_register_cipher.o src/misc/crypt/crypt_register_hash.o \
 src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \
 src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \
 src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/hkdf/hkdf.o \
-src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/pk_get_oid.o src/misc/pkcs5/pkcs_5_1.o \
+src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/padding/padding_depad.o \
+src/misc/padding/padding_pad.o src/misc/pk_get_oid.o src/misc/pkcs5/pkcs_5_1.o \
 src/misc/pkcs5/pkcs_5_2.o src/misc/pkcs5/pkcs_5_test.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o \
 src/modes/cbc/cbc_done.o src/modes/cbc/cbc_encrypt.o src/modes/cbc/cbc_getiv.o \
 src/modes/cbc/cbc_setiv.o src/modes/cbc/cbc_start.o src/modes/cfb/cfb_decrypt.o \
@@ -207,7 +208,7 @@ src/stream/sosemanuk/sosemanuk.o src/stream/sosemanuk/sosemanuk_test.o
 TOBJECTS=tests/base16_test.o tests/base32_test.o tests/base64_test.o tests/cipher_hash_test.o \
 tests/common.o tests/der_test.o tests/dh_test.o tests/dsa_test.o tests/ecc_test.o tests/file_test.o \
 tests/katja_test.o tests/mac_test.o tests/misc_test.o tests/modes_test.o tests/mpi_test.o \
-tests/multi_test.o tests/no_prng.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o \
+tests/multi_test.o tests/no_prng.o tests/padding_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o \
 tests/pkcs_1_oaep_test.o tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/prng_test.o \
 tests/rotate_test.o tests/rsa_test.o tests/store_test.o tests/test.o
 

+ 3 - 2
makefile.msvc

@@ -102,7 +102,8 @@ src/misc/crypt/crypt_register_cipher.obj src/misc/crypt/crypt_register_hash.obj
 src/misc/crypt/crypt_register_prng.obj src/misc/crypt/crypt_sizes.obj \
 src/misc/crypt/crypt_unregister_cipher.obj src/misc/crypt/crypt_unregister_hash.obj \
 src/misc/crypt/crypt_unregister_prng.obj src/misc/error_to_string.obj src/misc/hkdf/hkdf.obj \
-src/misc/hkdf/hkdf_test.obj src/misc/mem_neq.obj src/misc/pk_get_oid.obj src/misc/pkcs5/pkcs_5_1.obj \
+src/misc/hkdf/hkdf_test.obj src/misc/mem_neq.obj src/misc/padding/padding_depad.obj \
+src/misc/padding/padding_pad.obj src/misc/pk_get_oid.obj src/misc/pkcs5/pkcs_5_1.obj \
 src/misc/pkcs5/pkcs_5_2.obj src/misc/pkcs5/pkcs_5_test.obj src/misc/zeromem.obj src/modes/cbc/cbc_decrypt.obj \
 src/modes/cbc/cbc_done.obj src/modes/cbc/cbc_encrypt.obj src/modes/cbc/cbc_getiv.obj \
 src/modes/cbc/cbc_setiv.obj src/modes/cbc/cbc_start.obj src/modes/cfb/cfb_decrypt.obj \
@@ -200,7 +201,7 @@ src/stream/sosemanuk/sosemanuk.obj src/stream/sosemanuk/sosemanuk_test.obj
 TOBJECTS=tests/base16_test.obj tests/base32_test.obj tests/base64_test.obj tests/cipher_hash_test.obj \
 tests/common.obj tests/der_test.obj tests/dh_test.obj tests/dsa_test.obj tests/ecc_test.obj tests/file_test.obj \
 tests/katja_test.obj tests/mac_test.obj tests/misc_test.obj tests/modes_test.obj tests/mpi_test.obj \
-tests/multi_test.obj tests/no_prng.obj tests/pkcs_1_eme_test.obj tests/pkcs_1_emsa_test.obj \
+tests/multi_test.obj tests/no_prng.obj tests/padding_test.obj tests/pkcs_1_eme_test.obj tests/pkcs_1_emsa_test.obj \
 tests/pkcs_1_oaep_test.obj tests/pkcs_1_pss_test.obj tests/pkcs_1_test.obj tests/prng_test.obj \
 tests/rotate_test.obj tests/rsa_test.obj tests/store_test.obj tests/test.obj
 

+ 3 - 2
makefile.unix

@@ -119,7 +119,8 @@ src/misc/crypt/crypt_register_cipher.o src/misc/crypt/crypt_register_hash.o \
 src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \
 src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \
 src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/hkdf/hkdf.o \
-src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/pk_get_oid.o src/misc/pkcs5/pkcs_5_1.o \
+src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/padding/padding_depad.o \
+src/misc/padding/padding_pad.o src/misc/pk_get_oid.o src/misc/pkcs5/pkcs_5_1.o \
 src/misc/pkcs5/pkcs_5_2.o src/misc/pkcs5/pkcs_5_test.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o \
 src/modes/cbc/cbc_done.o src/modes/cbc/cbc_encrypt.o src/modes/cbc/cbc_getiv.o \
 src/modes/cbc/cbc_setiv.o src/modes/cbc/cbc_start.o src/modes/cfb/cfb_decrypt.o \
@@ -217,7 +218,7 @@ src/stream/sosemanuk/sosemanuk.o src/stream/sosemanuk/sosemanuk_test.o
 TOBJECTS=tests/base16_test.o tests/base32_test.o tests/base64_test.o tests/cipher_hash_test.o \
 tests/common.o tests/der_test.o tests/dh_test.o tests/dsa_test.o tests/ecc_test.o tests/file_test.o \
 tests/katja_test.o tests/mac_test.o tests/misc_test.o tests/modes_test.o tests/mpi_test.o \
-tests/multi_test.o tests/no_prng.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o \
+tests/multi_test.o tests/no_prng.o tests/padding_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o \
 tests/pkcs_1_oaep_test.o tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/prng_test.o \
 tests/rotate_test.o tests/rsa_test.o tests/store_test.o tests/test.o
 

+ 3 - 2
makefile_include.mk

@@ -259,7 +259,8 @@ src/misc/crypt/crypt_register_cipher.o src/misc/crypt/crypt_register_hash.o \
 src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \
 src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \
 src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/hkdf/hkdf.o \
-src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/pk_get_oid.o src/misc/pkcs5/pkcs_5_1.o \
+src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/padding/padding_depad.o \
+src/misc/padding/padding_pad.o src/misc/pk_get_oid.o src/misc/pkcs5/pkcs_5_1.o \
 src/misc/pkcs5/pkcs_5_2.o src/misc/pkcs5/pkcs_5_test.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o \
 src/modes/cbc/cbc_done.o src/modes/cbc/cbc_encrypt.o src/modes/cbc/cbc_getiv.o \
 src/modes/cbc/cbc_setiv.o src/modes/cbc/cbc_start.o src/modes/cfb/cfb_decrypt.o \
@@ -357,7 +358,7 @@ src/stream/sosemanuk/sosemanuk.o src/stream/sosemanuk/sosemanuk_test.o
 TOBJECTS=tests/base16_test.o tests/base32_test.o tests/base64_test.o tests/cipher_hash_test.o \
 tests/common.o tests/der_test.o tests/dh_test.o tests/dsa_test.o tests/ecc_test.o tests/file_test.o \
 tests/katja_test.o tests/mac_test.o tests/misc_test.o tests/modes_test.o tests/mpi_test.o \
-tests/multi_test.o tests/no_prng.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o \
+tests/multi_test.o tests/no_prng.o tests/padding_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o \
 tests/pkcs_1_oaep_test.o tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/prng_test.o \
 tests/rotate_test.o tests/rsa_test.o tests/store_test.o tests/test.o
 

+ 2 - 0
src/headers/tomcrypt_custom.h

@@ -464,6 +464,8 @@
 
 #define LTC_CRC32
 
+#define LTC_PADDING
+
 #endif /* LTC_NO_MISC */
 
 /* cleanup */

+ 23 - 0
src/headers/tomcrypt_misc.h

@@ -135,6 +135,29 @@ void crc32_finish(crc32_state *ctx, void *hash, unsigned long size);
 int crc32_test(void);
 #endif
 
+
+#ifdef LTC_PADDING
+
+enum padding_type {
+   LTC_PAD_PKCS7        = 0x0000U,
+#ifdef LTC_RNG_GET_BYTES
+   LTC_PAD_ISO_10126    = 0x1000U,
+#endif
+   LTC_PAD_ANSI_X923    = 0x2000U,
+   LTC_PAD_ONE_AND_ZERO = 0x8000U,
+   LTC_PAD_ZERO         = 0x9000U,
+   LTC_PAD_ZERO_ALWAYS  = 0xA000U,
+};
+
+int padding_pad(unsigned char *data, unsigned long length, unsigned long* padded_length, unsigned long mode);
+int padding_depad(unsigned char *data, unsigned long *length, unsigned long mode);
+
+#ifdef LTC_SOURCE
+/* internal helper functions */
+#define LTC_PAD_MASK       (0xF000U)
+#endif
+#endif  /* LTC_PADDING */
+
 int compare_testvector(const void* is, const unsigned long is_len, const void* should, const unsigned long should_len, const char* what, int which);
 
 /* ref:         $Format:%D$ */

+ 3 - 0
src/misc/crypt/crypt.c

@@ -429,6 +429,9 @@ const char *crypt_build_settings =
 #if defined(LTC_PKCS_5)
     " PKCS#5 "
 #endif
+#if defined(LTC_PADDING)
+    " PADDING "
+#endif
 #if defined(LTC_HKDF)
     " HKDF "
 #endif

+ 15 - 0
src/misc/crypt/crypt_constants.c

@@ -75,6 +75,21 @@ static const crypt_constant _crypt_constants[] = {
     {"LTC_PKCS_1", 0},
 #endif
 
+#ifdef LTC_PADDING
+    {"LTC_PADDING", 1},
+
+    _C_STRINGIFY(LTC_PAD_PKCS7),
+#ifdef LTC_RNG_GET_BYTES
+    _C_STRINGIFY(LTC_PAD_ISO_10126),
+#endif
+    _C_STRINGIFY(LTC_PAD_ANSI_X923),
+    _C_STRINGIFY(LTC_PAD_ONE_AND_ZERO),
+    _C_STRINGIFY(LTC_PAD_ZERO),
+    _C_STRINGIFY(LTC_PAD_ZERO_ALWAYS),
+#else
+    {"LTC_PADDING", 0},
+#endif
+
 #ifdef LTC_MRSA
     {"LTC_MRSA", 1},
 #else

+ 94 - 0
src/misc/padding/padding_depad.c

@@ -0,0 +1,94 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_PADDING
+
+/**
+   Remove padding from your data
+
+      This depads your data.
+
+   @param data     The data to depad
+   @param length   [in/out] The size of the data before/after (removing padding)
+   @param mode     One of the LTC_PAD_xx flags
+   @return CRYPT_OK on success
+*/
+int padding_depad(unsigned char *data, unsigned long *length, unsigned long mode)
+{
+   unsigned long padded_length, unpadded_length, n;
+   unsigned char pad;
+   enum padding_type type;
+
+   LTC_ARGCHK(data   != NULL);
+   LTC_ARGCHK(length != NULL);
+
+   padded_length = *length;
+
+   type = mode & LTC_PAD_MASK;
+
+   if (type < LTC_PAD_ONE_AND_ZERO) {
+      pad = data[padded_length - 1];
+
+      if (pad > padded_length) return CRYPT_INVALID_ARG;
+
+      unpadded_length = padded_length - pad;
+   } else {
+      /* init pad to calm old compilers */
+      pad = 0x0;
+      unpadded_length = padded_length;
+   }
+
+   switch (type) {
+      case LTC_PAD_ANSI_X923:
+         pad = 0x0;
+         /* FALLTHROUGH */
+      case LTC_PAD_PKCS7:
+         for (n = unpadded_length; n < padded_length - 1; ++n) {
+            if (data[n] != pad) return CRYPT_INVALID_PACKET;
+         }
+         break;
+#ifdef LTC_RNG_GET_BYTES
+      case LTC_PAD_ISO_10126:
+         /* nop */
+         break;
+#endif
+      case LTC_PAD_ONE_AND_ZERO:
+         while (unpadded_length > 0 && data[unpadded_length - 1] != 0x80) {
+            if (data[unpadded_length - 1] != 0x0) return CRYPT_INVALID_PACKET;
+            unpadded_length--;
+         }
+         if (unpadded_length == 0) return CRYPT_INVALID_PACKET;
+         unpadded_length--;
+         if (data[unpadded_length] != 0x80) return CRYPT_INVALID_PACKET;
+         break;
+      case LTC_PAD_ZERO:
+      case LTC_PAD_ZERO_ALWAYS:
+         while (unpadded_length > 0 && data[unpadded_length - 1] == 0x0) {
+            unpadded_length--;
+         }
+         if (type == LTC_PAD_ZERO_ALWAYS) {
+            if (unpadded_length == padded_length) return CRYPT_INVALID_PACKET;
+            if (data[unpadded_length] != 0x0) return CRYPT_INVALID_PACKET;
+         }
+         break;
+      default:
+         return CRYPT_INVALID_ARG;
+   }
+
+   *length = unpadded_length;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 146 - 0
src/misc/padding/padding_pad.c

@@ -0,0 +1,146 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_PADDING
+
+/**
+   Determine the to-be-padded length.
+
+   @param length     [in/out] The size of the data before/after padding
+   @param mode       Mask of (LTC_PAD_xxx | block_length)
+   @return CRYPT_OK on success
+*/
+static int _padding_padded_length(unsigned long *length, unsigned long mode)
+{
+   enum padding_type padding;
+   unsigned char pad, block_length, r, t;
+
+   LTC_ARGCHK(length != NULL);
+
+   block_length = mode & 0xff;
+   padding = mode & LTC_PAD_MASK;
+   r = *length % block_length;
+
+   switch (padding) {
+      case LTC_PAD_ZERO:
+         if (r == 0) {
+            t = 0;
+            break;
+         }
+         /* FALLTHROUGH */
+      case LTC_PAD_PKCS7:
+      case LTC_PAD_ONE_AND_ZERO:
+      case LTC_PAD_ZERO_ALWAYS:
+         t = 1;
+         break;
+#ifdef LTC_RNG_GET_BYTES
+      case LTC_PAD_ISO_10126:
+         do {
+            if (rng_get_bytes(&t, sizeof(t), NULL) != sizeof(t)) {
+               return CRYPT_ERROR_READPRNG;
+            }
+            t %= (256 / block_length);
+         } while (t == 0);
+         break;
+#endif
+      case LTC_PAD_ANSI_X923:
+         if (block_length != 16) {
+            return CRYPT_INVALID_ARG;
+         }
+         t = 1;
+         break;
+      default:
+         return CRYPT_INVALID_ARG;
+   }
+
+   pad = (t * block_length) - r;
+
+   if ((pad == 0) && (padding != LTC_PAD_ZERO)) {
+      pad = block_length;
+   }
+
+   *length += pad;
+
+   return CRYPT_OK;
+}
+
+/**
+   Add padding to data.
+
+      This pads your data.
+
+   @param data          The data to depad
+   @param length        The size of the data before padding
+   @param padded_length [in/out] The size of the data available/after padding
+   @param mode          One of the LTC_PAD_xx flags
+   @return CRYPT_OK on success
+*/
+int padding_pad(unsigned char *data, unsigned long length, unsigned long* padded_length, unsigned long mode)
+{
+   unsigned long diff, l;
+   enum padding_type type;
+   int err;
+
+   LTC_ARGCHK(data          != NULL);
+   LTC_ARGCHK(padded_length != NULL);
+
+   l = length;
+   if ((err = _padding_padded_length(&l, mode)) != CRYPT_OK) {
+      return err;
+   }
+
+   type = mode & LTC_PAD_MASK;
+
+   if (*padded_length < l) {
+      if (type != LTC_PAD_ISO_10126) *padded_length = l;
+      else *padded_length = length + 256;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   diff = l - length;
+   if (diff > 255) return CRYPT_INVALID_ARG;
+
+   switch (type) {
+      case LTC_PAD_PKCS7:
+         XMEMSET(&data[length], diff, diff);
+         break;
+#ifdef LTC_RNG_GET_BYTES
+      case LTC_PAD_ISO_10126:
+         if (rng_get_bytes(&data[length], diff-1, NULL) != diff-1) {
+            return CRYPT_ERROR_READPRNG;
+         }
+         data[l-1] =  diff;
+         break;
+#endif
+      case LTC_PAD_ANSI_X923:
+         XMEMSET(&data[length], 0, diff-1);
+         data[l-1] =  diff;
+         break;
+      case LTC_PAD_ONE_AND_ZERO:
+         XMEMSET(&data[length + 1], 0, diff);
+         data[length] =  0x80;
+         break;
+      case LTC_PAD_ZERO:
+      case LTC_PAD_ZERO_ALWAYS:
+         XMEMSET(&data[length], 0, diff);
+         break;
+      default:
+         return CRYPT_INVALID_ARG;
+   }
+   *padded_length = l;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 3 - 0
tests/misc_test.c

@@ -16,6 +16,9 @@ int misc_test(void)
 #ifdef LTC_PKCS_5
    DO(pkcs_5_test());
 #endif
+#ifdef LTC_PADDING
+   DO(padding_test());
+#endif
 #ifdef LTC_BASE64
    DO(base64_test());
 #endif

+ 204 - 0
tests/padding_test.c

@@ -0,0 +1,204 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include  <tomcrypt_test.h>
+
+#ifdef LTC_PADDING
+
+typedef struct padding_testcase_ padding_testcase;
+
+typedef int (*cmp_padding_testcase)(const padding_testcase*, const unsigned char*, unsigned long);
+
+struct padding_testcase_ {
+   unsigned long is, should, max, mode;
+   const char* name;
+   cmp_padding_testcase cmp;
+};
+
+#define EQ(a, b) _eq((a), (b), #a, #b)
+
+static int _eq(unsigned long a, unsigned long b, const char* _a, const char* _b)
+{
+   if (a == b) return CRYPT_OK;
+#if defined(LTC_TEST) && defined(LTC_TEST_DBG)
+   else fprintf(stderr, "'%s == %s' failed, %lu is not equal to %lu\n", _a, _b, a, b);
+#else
+   LTC_UNUSED_PARAM(_a);
+   LTC_UNUSED_PARAM(_b);
+#endif
+   return CRYPT_FAIL_TESTVECTOR;
+}
+
+static int _cmp_pkcs7(const padding_testcase* t, const unsigned char* p, unsigned long len)
+{
+   unsigned long n, diff = len - t->is;
+   DOX(EQ(len, t->should), t->name);
+   for (n = len - diff; n < len; ++n) {
+      DOX(EQ(p[n], diff), t->name);
+   }
+   return CRYPT_OK;
+}
+
+#ifdef LTC_RNG_GET_BYTES
+static int _cmp_iso_10126(const padding_testcase* t, const unsigned char* p, unsigned long len)
+{
+   LTC_UNUSED_PARAM(p);
+   if (len < t->should || len > t->max) {
+#if defined(LTC_TEST) && defined(LTC_TEST_DBG)
+      fprintf(stderr, "(%lu < %lu || %lu > %lu) failed, %s\n", len, t->should, len, t->max, t->name);
+#endif
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+   DOX(EQ(p[len - 1], len - t->is), t->name);
+   return CRYPT_OK;
+}
+#endif
+
+static int _cmp_x923(const padding_testcase* t, const unsigned char* p, unsigned long len)
+{
+   unsigned long n, diff = len - t->is;
+   DOX(EQ(len, t->should), t->name);
+   for (n = len - diff; n < len - 1; ++n) {
+      DOX(EQ(p[n], 0x0), t->name);
+   }
+   DOX(EQ(p[len - 1], diff), t->name);
+   return CRYPT_OK;
+}
+
+static int _cmp_oaz(const padding_testcase* t, const unsigned char* p, unsigned long len)
+{
+   unsigned long n, diff = len - t->is;
+   DOX(EQ(len, t->should), t->name);
+   n = len - diff;
+   DOX(EQ(p[n], 0x80), t->name);
+   n++;
+   for (; n < len; ++n) {
+      DOX(EQ(p[n], 0x0), t->name);
+   }
+   return CRYPT_OK;
+}
+
+static int _cmp_zero(const padding_testcase* t, const unsigned char* p, unsigned long len)
+{
+   unsigned long n, diff = len - t->is;
+   DOX(EQ(len, t->should), t->name);
+   for (n = len - diff; n < len; ++n) {
+      DOX(EQ(p[n], 0x0), t->name);
+   }
+   return CRYPT_OK;
+}
+
+static int _padding_testrun(const padding_testcase* t)
+{
+   unsigned long len;
+   unsigned char buf[1024];
+
+   len = sizeof(buf);
+   XMEMSET(buf, 0xAA, t->is);
+   DO(padding_pad(buf, t->is, &len, t->mode));
+   DO(t->cmp(t, buf, len));
+   DO(padding_depad(buf, &len, t->mode));
+   DO(EQ(len, t->is));
+   return CRYPT_OK;
+}
+
+int padding_test(void)
+{
+   const padding_testcase cases[] = {
+                             {   0,  16,   0, LTC_PAD_PKCS7 | 16, "0-pkcs7",     _cmp_pkcs7 },
+                             {   1,  16,   0, LTC_PAD_PKCS7 | 16, "1-pkcs7",     _cmp_pkcs7 },
+                             {  15,  16,   0, LTC_PAD_PKCS7 | 16, "15-pkcs7",    _cmp_pkcs7 },
+                             {  16,  32,   0, LTC_PAD_PKCS7 | 16, "16-pkcs7",    _cmp_pkcs7 },
+                             { 255, 256,   0, LTC_PAD_PKCS7 | 16, "255-pkcs7",   _cmp_pkcs7 },
+                             { 256, 272,   0, LTC_PAD_PKCS7 | 16, "256-pkcs7",   _cmp_pkcs7 },
+#ifdef LTC_RNG_GET_BYTES
+                             {   0,  16, 256, LTC_PAD_ISO_10126 | 16, "0-rand",     _cmp_iso_10126 },
+                             {   1,  16, 272, LTC_PAD_ISO_10126 | 16, "1-rand",     _cmp_iso_10126 },
+                             {  15,  16, 272, LTC_PAD_ISO_10126 | 16, "15-rand",    _cmp_iso_10126 },
+                             {  16,  32, 288, LTC_PAD_ISO_10126 | 16, "16-rand",    _cmp_iso_10126 },
+                             { 255, 256, 512, LTC_PAD_ISO_10126 | 16, "255-rand",   _cmp_iso_10126 },
+                             { 256, 272, 528, LTC_PAD_ISO_10126 | 16, "256-rand",   _cmp_iso_10126 },
+#endif
+                             {   0,  16,   0, LTC_PAD_ANSI_X923 | 16, "0-x923",   _cmp_x923 },
+                             {   1,  16,   0, LTC_PAD_ANSI_X923 | 16, "1-x923",   _cmp_x923 },
+                             {  15,  16,   0, LTC_PAD_ANSI_X923 | 16, "15-x923",  _cmp_x923 },
+                             {  16,  32,   0, LTC_PAD_ANSI_X923 | 16, "16-x923",  _cmp_x923 },
+                             { 255, 256,   0, LTC_PAD_ANSI_X923 | 16, "255-x923", _cmp_x923 },
+                             { 256, 272,   0, LTC_PAD_ANSI_X923 | 16, "256-x923", _cmp_x923 },
+
+                             {   0,  16,   0, LTC_PAD_ONE_AND_ZERO | 16, "0-one-and-zero",   _cmp_oaz },
+                             {   1,  16,   0, LTC_PAD_ONE_AND_ZERO | 16, "1-one-and-zero",   _cmp_oaz },
+                             {  15,  16,   0, LTC_PAD_ONE_AND_ZERO | 16, "15-one-and-zero",  _cmp_oaz },
+                             {  16,  32,   0, LTC_PAD_ONE_AND_ZERO | 16, "16-one-and-zero",  _cmp_oaz },
+                             { 255, 256,   0, LTC_PAD_ONE_AND_ZERO | 16, "255-one-and-zero", _cmp_oaz },
+                             { 256, 272,   0, LTC_PAD_ONE_AND_ZERO | 16, "256-one-and-zero", _cmp_oaz },
+
+                             {   0,   0,   0, LTC_PAD_ZERO | 16, "0-zero",   _cmp_zero },
+                             {   1,  16,   0, LTC_PAD_ZERO | 16, "1-zero",   _cmp_zero },
+                             {  15,  16,   0, LTC_PAD_ZERO | 16, "15-zero",  _cmp_zero },
+                             {  16,  16,   0, LTC_PAD_ZERO | 16, "16-zero",  _cmp_zero },
+                             { 255, 256,   0, LTC_PAD_ZERO | 16, "255-zero", _cmp_zero },
+                             { 256, 256,   0, LTC_PAD_ZERO | 16, "256-zero", _cmp_zero },
+
+                             {   0,  16,   0, LTC_PAD_ZERO_ALWAYS | 16, "0-zero-always",   _cmp_zero },
+                             {   1,  16,   0, LTC_PAD_ZERO_ALWAYS | 16, "1-zero-always",   _cmp_zero },
+                             {  15,  16,   0, LTC_PAD_ZERO_ALWAYS | 16, "15-zero-always",  _cmp_zero },
+                             {  16,  32,   0, LTC_PAD_ZERO_ALWAYS | 16, "16-zero-always",  _cmp_zero },
+                             { 255, 256,   0, LTC_PAD_ZERO_ALWAYS | 16, "255-zero-always", _cmp_zero },
+                             { 256, 272,   0, LTC_PAD_ZERO_ALWAYS | 16, "256-zero-always", _cmp_zero },
+   };
+   unsigned i;
+   /* Examples from https://en.wikipedia.org/w/index.php?title=Padding_(cryptography)&oldid=823057951#Byte_padding */
+   const struct {
+      unsigned char data[16];
+      unsigned long len;
+      unsigned long mode;
+   } tv[] = {
+      { { 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x04, 0x04, 0x04, 0x04 }, 12, LTC_PAD_PKCS7 | 16 },
+      { { 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x00, 0x00, 0x00, 0x04 }, 12, LTC_PAD_ANSI_X923 | 16 },
+#ifdef LTC_RNG_GET_BYTES
+      { { 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x81, 0xA6, 0x23, 0x04 }, 12, LTC_PAD_ISO_10126 | 16 },
+#endif
+      { { 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x80, 0x00, 0x00, 0x00 }, 12, LTC_PAD_ONE_AND_ZERO | 16 },
+      { { 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x80 }, 15, LTC_PAD_ONE_AND_ZERO | 16 },
+      { { 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x00, 0x00, 0x00, 0x00 }, 12, LTC_PAD_ZERO | 16 },
+   };
+   /* we need a big buffer like that as LTC_PAD_ISO_10126
+    * is allowed to add 1-255 bytes of padding
+    */
+   unsigned char buf[256 + 16];
+   unsigned long l;
+
+   for (i = 0; i < sizeof(cases)/sizeof(cases[0]); ++i) {
+      DOX(_padding_testrun(&cases[i]), cases[i].name);
+   }
+
+   for (i = 0; i < sizeof(tv)/sizeof(tv[0]); ++i) {
+      XMEMCPY(buf, tv[i].data, sizeof(tv[i].data));
+      l = sizeof(tv[i].data);
+      DO(padding_depad(buf, &l, tv[i].mode));
+      XMEMSET(buf, 0xDD, 16);
+      l = sizeof(buf);
+      DO(padding_pad(buf, tv[i].len, &l, tv[i].mode));
+#ifdef LTC_RNG_GET_BYTES
+      if ((tv[i].mode & LTC_PAD_MASK) != LTC_PAD_ISO_10126)
+#endif
+      {
+         DO(compare_testvector(tv[i].data, sizeof(tv[i].data), buf, l, "padding fixed TV", i) == 0 ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR);
+      }
+   }
+
+
+   return CRYPT_OK;
+}
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 2 - 0
tests/tomcrypt_test.h

@@ -44,6 +44,8 @@ int file_test(void);
 int multi_test(void);
 int prng_test(void);
 int mpi_test(void);
+int padding_test(void);
+
 
 #ifdef LTC_PKCS_1
 struct ltc_prng_descriptor* no_prng_desc_get(void);