Browse Source

Merge pull request #343 from libtom/feature/pkcs7

Add padding/depadding support
Steffen Jaeckel 7 years ago
parent
commit
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
  * Output:       number of bytes after padding resp. after unpadding
  * Side Effects: none
  * 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)
                  int is_padding)
 {
 {
-   unsigned char padval;
-   off_t idx;
+   unsigned long length;
 
 
    if(is_padding) {
    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 {
    } 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;
          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
          /* We're encrypting, so pad first (if at EOF) and then
             crypt */
             crypt */
          if(feof(infd))
          if(feof(infd))
-            nb = pkcs7_pad(&inbuf, nb,
+            nb = _pkcs7_pad(&inbuf, nb,
                            aes_desc.block_length, 1);
                            aes_desc.block_length, 1);
 
 
          ret = cbc_encrypt(inbuf.pad, outbuf.pad, nb, &cbc);
          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 )
          if( ret != CRYPT_OK )
             return ret;
             return ret;
 
 
-         if( feof(infd) )
-            nb = pkcs7_pad(&outbuf, nb,
+         if(feof(infd))
+            nb = _pkcs7_pad(&outbuf, nb,
                            aes_desc.block_length, 0);
                            aes_desc.block_length, 0);
          if(nb == 0)
          if(nb == 0)
             /* The file didn't decrypt correctly */
             /* 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);
                         unsigned char *out, unsigned long *outlen);
 \end{verbatim}
 \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}
 \mysection{Primality Testing}
 \index{Primality Testing}
 \index{Primality Testing}
 The library includes primality testing and random prime functions as well.  The primality tester will perform the test in
 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>
 				</File>
 			</Filter>
 			</Filter>
+			<Filter
+				Name="padding"
+				>
+				<File
+					RelativePath="src\misc\padding\padding_depad.c"
+					>
+				</File>
+				<File
+					RelativePath="src\misc\padding\padding_pad.c"
+					>
+				</File>
+			</Filter>
 			<Filter
 			<Filter
 				Name="pkcs5"
 				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_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_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/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/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_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 \
 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 \
 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/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/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/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
 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_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_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/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/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_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 \
 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 \
 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/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/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/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
 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_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_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/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/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_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 \
 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 \
 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/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/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/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
 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_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_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/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/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_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 \
 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 \
 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/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/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/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
 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_CRC32
 
 
+#define LTC_PADDING
+
 #endif /* LTC_NO_MISC */
 #endif /* LTC_NO_MISC */
 
 
 /* cleanup */
 /* 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);
 int crc32_test(void);
 #endif
 #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);
 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$ */
 /* ref:         $Format:%D$ */

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

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

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

@@ -75,6 +75,21 @@ static const crypt_constant _crypt_constants[] = {
     {"LTC_PKCS_1", 0},
     {"LTC_PKCS_1", 0},
 #endif
 #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
 #ifdef LTC_MRSA
     {"LTC_MRSA", 1},
     {"LTC_MRSA", 1},
 #else
 #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
 #ifdef LTC_PKCS_5
    DO(pkcs_5_test());
    DO(pkcs_5_test());
 #endif
 #endif
+#ifdef LTC_PADDING
+   DO(padding_test());
+#endif
 #ifdef LTC_BASE64
 #ifdef LTC_BASE64
    DO(base64_test());
    DO(base64_test());
 #endif
 #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 multi_test(void);
 int prng_test(void);
 int prng_test(void);
 int mpi_test(void);
 int mpi_test(void);
+int padding_test(void);
+
 
 
 #ifdef LTC_PKCS_1
 #ifdef LTC_PKCS_1
 struct ltc_prng_descriptor* no_prng_desc_get(void);
 struct ltc_prng_descriptor* no_prng_desc_get(void);