1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 #ifdef LTC_PADDING
6 
7 /**
8    Determine the to-be-padded length.
9 
10    @param length     [in/out] The size of the data before/after padding
11    @param mode       Mask of (LTC_PAD_xxx | block_length)
12    @return CRYPT_OK on success
13 */
s_padding_padded_length(unsigned long * length,unsigned long mode)14 static int s_padding_padded_length(unsigned long *length, unsigned long mode)
15 {
16    enum padding_type padding;
17    unsigned char pad, block_length, r, t;
18 
19    LTC_ARGCHK(length != NULL);
20 
21    block_length = mode & 0xff;
22    padding = mode & LTC_PAD_MASK;
23    r = *length % block_length;
24 
25    switch (padding) {
26       case LTC_PAD_ZERO:
27          if (r == 0) {
28             t = 0;
29             break;
30          }
31          /* FALLTHROUGH */
32       case LTC_PAD_PKCS7:
33       case LTC_PAD_ONE_AND_ZERO:
34       case LTC_PAD_ZERO_ALWAYS:
35       case LTC_PAD_SSH:
36          t = 1;
37          break;
38 #ifdef LTC_RNG_GET_BYTES
39       case LTC_PAD_ISO_10126:
40          do {
41             if (rng_get_bytes(&t, sizeof(t), NULL) != sizeof(t)) {
42                return CRYPT_ERROR_READPRNG;
43             }
44             t %= (256 / block_length);
45          } while (t == 0);
46          break;
47 #endif
48       case LTC_PAD_ANSI_X923:
49          if (block_length != 16) {
50             return CRYPT_INVALID_ARG;
51          }
52          t = 1;
53          break;
54       default:
55          return CRYPT_INVALID_ARG;
56    }
57 
58    pad = (t * block_length) - r;
59 
60    if ((pad == 0) && (padding != LTC_PAD_ZERO)) {
61       pad = block_length;
62    }
63 
64    *length += pad;
65 
66    return CRYPT_OK;
67 }
68 
69 /**
70    Add padding to data.
71 
72       This pads your data.
73 
74    @param data          The data to depad
75    @param length        The size of the data before padding
76    @param padded_length [in/out] The size of the data available/after padding
77    @param mode          One of the LTC_PAD_xx flags
78    @return CRYPT_OK on success
79 */
padding_pad(unsigned char * data,unsigned long length,unsigned long * padded_length,unsigned long mode)80 int padding_pad(unsigned char *data, unsigned long length, unsigned long* padded_length, unsigned long mode)
81 {
82    unsigned long l, n;
83    enum padding_type type;
84    int err;
85    unsigned char diff, pad;
86 
87    LTC_ARGCHK(data          != NULL);
88    LTC_ARGCHK(padded_length != NULL);
89 
90    l = length;
91    if ((err = s_padding_padded_length(&l, mode)) != CRYPT_OK) {
92       return err;
93    }
94 
95    type = mode & LTC_PAD_MASK;
96 
97    if (*padded_length < l) {
98 #ifdef LTC_RNG_GET_BYTES
99       if (type != LTC_PAD_ISO_10126) {
100          *padded_length = l;
101       } else {
102          *padded_length = length + 256;
103       }
104 #else
105       *padded_length = l;
106 #endif
107       return CRYPT_BUFFER_OVERFLOW;
108    }
109 
110    if (l - length > 255) return CRYPT_INVALID_ARG;
111    diff = (unsigned char)(l - length);
112 
113    switch (type) {
114       case LTC_PAD_PKCS7:
115          XMEMSET(&data[length], diff, diff);
116          break;
117 #ifdef LTC_RNG_GET_BYTES
118       case LTC_PAD_ISO_10126:
119          if (rng_get_bytes(&data[length], diff-1u, NULL) != diff-1u) {
120             return CRYPT_ERROR_READPRNG;
121          }
122          data[l-1] =  diff;
123          break;
124 #endif
125       case LTC_PAD_ANSI_X923:
126          XMEMSET(&data[length], 0, diff-1);
127          data[l-1] =  diff;
128          break;
129       case LTC_PAD_SSH:
130          pad = 0x1;
131          for (n = length; n < l; ++n) {
132             data[n] = pad++;
133          }
134          break;
135       case LTC_PAD_ONE_AND_ZERO:
136          XMEMSET(&data[length + 1], 0, diff);
137          data[length] =  0x80;
138          break;
139       case LTC_PAD_ZERO:
140       case LTC_PAD_ZERO_ALWAYS:
141          XMEMSET(&data[length], 0, diff);
142          break;
143       default:
144          return CRYPT_INVALID_ARG;
145    }
146    *padded_length = l;
147 
148    return CRYPT_OK;
149 }
150 
151 #endif
152