1 /**
2 * ECB/CBC Padding Methods
3 * 
4 * Copyright:
5 * (C) 1999-2008,2013 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.modes.mode_pad;
12 
13 import memutils.vector;
14 import botan.utils.exceptn;
15 import botan.constants;
16 
17 /**
18 * Block Cipher Mode Padding Method
19 * This class is pretty limited, it cannot deal well with
20 * randomized padding methods, or any padding method that
21 * wants to add more than one block. For instance, it should
22 * be possible to define cipher text stealing mode as simply
23 * a padding mode for CBC, which happens to consume the last
24 * two block (and requires use of the block cipher).
25 */
26 interface BlockCipherModePaddingMethod
27 {
28 public:
29     abstract void addPadding(ref SecureVector!ubyte buffer, size_t final_block_bytes, size_t block_size) const;
30 
31     /**
32     * Params:
33     *  block = the last block
34     *  size = the of the block
35     */
36     abstract size_t unpad(const(ubyte)* block,
37                                 size_t size) const;
38 
39     /**
40     * Params:
41     *  block_size = of the cipher
42     * Returns: valid block size for this padding mode
43     */
44     abstract bool validBlocksize(size_t block_size) const;
45 
46     /**
47     * Returns: name of the mode
48     */
49     abstract @property string name() const;
50 
51 }
52 
53 /**
54 * PKCS#7 Padding
55 */
56 final class PKCS7Padding : BlockCipherModePaddingMethod
57 {
58 public:
59     /*
60     * Pad with PKCS #7 Method
61     */
62     override void addPadding(ref SecureVector!ubyte buffer, size_t last_byte_pos, size_t block_size) const
63     {
64         const ubyte pad_value = cast(ubyte)( block_size - last_byte_pos );
65         
66         foreach (size_t i; 0 .. pad_value)
67             buffer.pushBack(cast(ubyte)pad_value);
68     }
69 
70     /*
71     * Unpad with PKCS #7 Method
72     */
73     override size_t unpad(const(ubyte)* block, size_t size) const
74     {
75         size_t position = block[size-1];
76         
77         if (position > size)
78             throw new DecodingError("Bad padding in " ~ name);
79         
80         foreach (size_t j; (size-position) .. (size-1))
81             if (block[j] != position)
82                 throw new DecodingError("Bad padding in " ~ name);
83         
84         return (size-position);
85     }
86 
87     override bool validBlocksize(size_t bs) const { return (bs > 0 && bs < 256); }
88 
89     override @property string name() const { return "PKCS7"; }
90 }
91 
92 /**
93 * ANSI X9.23 Padding
94 */
95 final class ANSIX923Padding : BlockCipherModePaddingMethod
96 {
97 public:
98     /*
99     * Pad with ANSI X9.23 Method
100     */
101     override void addPadding(ref SecureVector!ubyte buffer,
102                                  size_t last_byte_pos,
103                                  size_t block_size) const
104     {
105         const ubyte pad_value = cast(ubyte) (block_size - last_byte_pos);
106         
107         for (size_t i = last_byte_pos; i < block_size; ++i)
108             buffer.pushBack(0);
109         buffer.pushBack(pad_value);
110     }
111 
112     /*
113     * Unpad with ANSI X9.23 Method
114     */
115     override size_t unpad(const(ubyte)* block, size_t size) const
116     {
117         size_t position = block[size-1];
118         if (position > size)
119             throw new DecodingError(name);
120         foreach (size_t j; (size-position) .. (size-1))
121             if (block[j] != 0)
122                 throw new DecodingError(name);
123         return (size-position);
124     }
125 
126     override bool validBlocksize(size_t bs) const { return (bs > 0 && bs < 256); }
127 
128     override @property string name() const { return "X9.23"; }
129 }
130 
131 /**
132 * One And Zeros Padding
133 */
134 final class OneAndZerosPadding : BlockCipherModePaddingMethod
135 {
136 public:
137     /*
138     * Pad with One and Zeros Method
139     */
140     override void addPadding(ref SecureVector!ubyte buffer, size_t last_byte_pos, size_t block_size) const
141     {
142         buffer.pushBack(0x80);
143         
144         for (size_t i = last_byte_pos + 1; i % block_size; ++i)
145             buffer.pushBack(0x00);
146     }
147 
148     /*
149     * Unpad with One and Zeros Method
150     */
151     override size_t unpad(const(ubyte)* block, size_t size) const
152     {
153         while (size)
154         {
155             if (block[size-1] == 0x80)
156                 break;
157             if (block[size-1] != 0x00)
158                 throw new DecodingError(name);
159             size--;
160         }
161         if (!size)
162             throw new DecodingError(name);
163         return (size-1);
164     }
165 
166     override bool validBlocksize(size_t bs) const { return (bs > 0); }
167 
168     override @property string name() const { return "OneAndZeros"; }
169 }
170 
171 /**
172 * Null Padding
173 */
174 final class NullPadding : BlockCipherModePaddingMethod
175 {
176 public:
177     override void addPadding(ref SecureVector!ubyte, size_t, size_t) const {}
178 
179     override size_t unpad(const(ubyte)*, size_t size) const { return size; }
180 
181     override bool validBlocksize(size_t) const { return true; }
182 
183     override @property string name() const { return "NoPadding"; }
184 }