Source code: cryptix/jce/provider/cipher/Padding.java
1 /* $Id: Padding.java,v 1.20 2005/03/28 15:44:53 woudt Exp $
2 *
3 * Copyright (C) 1995-2000 The Cryptix Foundation Limited.
4 * All rights reserved.
5 *
6 * Use, modification, copying and distribution of this software is subject
7 * the terms and conditions of the Cryptix General Licence. You should have
8 * received a copy of the Cryptix General Licence along with this library;
9 * if not, you can download a copy from http://www.cryptix.org/ .
10 */
11 package cryptix.jce.provider.cipher;
12
13
14 import java.security.InvalidAlgorithmParameterException;
15 import java.security.InvalidKeyException;
16 import java.security.Key;
17 import java.security.SecureRandom;
18 import java.security.spec.AlgorithmParameterSpec;
19 import javax.crypto.ShortBufferException;
20 import javax.crypto.IllegalBlockSizeException;
21 import javax.crypto.BadPaddingException;
22 import javax.crypto.NoSuchPaddingException;
23
24
25 /**
26 * <p>
27 * A fully constructed Cipher instance looks like this:
28 * <pre>
29 * +------------------------------------------+
30 * | CipherSpi (API methods) |
31 * | |
32 * | +--------------------------------------+ |
33 * | | Padding | |
34 * | | | |
35 * | | +----------------------------------+ | |
36 * | | | Mode | | |
37 * | | | | | |
38 * | | | +------------------------------+ | | |
39 * | | | | CipherSpi | | | |
40 * | | | | (blockcipher implementation) | | | |
41 * | | | | | | | |
42 * | | | +------------------------------+ | | |
43 * | | | | | |
44 * | | +----------------------------------+ | |
45 * | | | |
46 * | +--------------------------------------+ |
47 * | |
48 * +------------------------------------------+
49 * </pre>
50 *
51 * @author Jeroen C. van Gelderen (gelderen@cryptix.org)
52 * @author Paul Waserbrot (pw@cryptix.org)
53 * @version $Revision: 1.20 $
54 */
55 abstract class Padding
56 {
57 /** Cipher/Mode delegate */
58 private final Mode mode;
59
60
61 private byte[] scratchBuf;
62 private int blSize;
63 private boolean isBuffered;
64
65
66 protected boolean decrypt;
67
68
69 Padding(Mode mode) {
70 this.mode = mode;
71 blSize = this.getBlockSize();
72 scratchBuf = new byte[blSize];
73 isBuffered = false;
74 }
75
76
77 /**
78 * Factory method for obtaining different padding type objects.
79 *
80 * This method accept a padding name and a Mode instance and
81 * returns a Padding instance that wraps the given Mode instance.
82 *
83 * This class is package protected therefore the various padding
84 * types can be (and are) hardcoded here.
85 *
86 * @throws NoSuchPaddingException
87 * When the requested padding type cannot be provided.
88 */
89 static Padding getInstance(String padding, Mode mode)
90 throws NoSuchPaddingException
91 {
92 // Debug.assert(padding!=null);
93 // Debug.assert(mode!=null);
94
95 // None
96 if( padding.equalsIgnoreCase("None")
97 || padding.equalsIgnoreCase("NoPadding") )
98 return new PaddingNone(mode);
99
100 // Generalized PKCS#5 (aka PKCS#7)
101 if( padding.equalsIgnoreCase("PKCS5")
102 || padding.equalsIgnoreCase("PKCS#5")
103 || padding.equalsIgnoreCase("PKCS5Padding")
104 || padding.equalsIgnoreCase("PKCS7")
105 || padding.equalsIgnoreCase("PKCS#7") )
106 return new PaddingPKCS5(mode);
107
108 // Oops, not supported
109 throw new NoSuchPaddingException(
110 "Padding not available [" + padding + "]");
111 }
112
113
114 /**
115 * This method delegates to the wrapped Mode instance.
116 */
117 final int getBlockSize() {
118 return mode.getBlockSize();
119 }
120
121
122 final int getOutputSize(int inputLen) {
123 if (isBuffered)
124 return mode.getOutputSize(inputLen + this.getPadSize(inputLen))
125 + blSize;
126 else
127 return mode.getOutputSize(inputLen + this.getPadSize(inputLen));
128 }
129
130
131 /**
132 * This method delegates to the wrapped Mode instance.
133 */
134 final AlgorithmParameterSpec getParamSpec() {
135 return mode.getParamSpec();
136 }
137
138
139 /**
140 * This method delegates to the wrapped Mode instance.
141 */
142 final byte[] getIV() {
143 return mode.getIV();
144 }
145
146
147 /**
148 * This method delegates to the wrapped Mode instance.
149 */
150 final void init(boolean decrypt, Key key, AlgorithmParameterSpec params,
151 SecureRandom random)
152 throws InvalidKeyException, InvalidAlgorithmParameterException
153 {
154 mode.init(this.decrypt = decrypt, key, params, random);
155 }
156
157
158 /**
159 * This method delegates to the wrapped Mode instance.
160 *
161 * @throws ShortBufferException
162 * If output is too short to hold the result.
163 */
164 final int update(byte[] input, int inputOffset, int inputLen,
165 byte[] output, int outputOffset)
166 throws ShortBufferException
167 {
168 if (output.length < this.getOutputSize(inputLen))
169 throw new ShortBufferException("The output buffer is too short");
170
171 if (decrypt) {
172 int i = 0;
173 if (!isBuffered) {
174 i = mode.update(input, inputOffset, inputLen - blSize,
175 output, outputOffset);
176 System.arraycopy(input, inputOffset + (inputLen - blSize),
177 scratchBuf, 0, blSize);
178 isBuffered = true;
179 } else {
180 i = mode.update(scratchBuf, 0, blSize, output, outputOffset);
181 System.arraycopy(input, inputOffset + (inputLen - blSize),
182 scratchBuf, 0, blSize);
183 i += mode.update(input, inputOffset, inputLen - blSize,
184 output, outputOffset + blSize);
185 }
186 return i;
187 } else
188 return mode.update(input, inputOffset, inputLen,
189 output, outputOffset);
190 }
191
192 /**
193 * @throws BadPaddingException
194 * If the padding data is corrupt or not found (decrypt only).
195 * @throws IllegalBlockSizeException
196 * If no padding is specified *and* the input data was not a
197 * multiple of the Cipher's blocksize.
198 * @throws ShortBufferException
199 * If output is too short to hold the result.
200 */
201 final int doFinal(byte[] input, int inputOffset, int inputLen,
202 byte[] output, int outputOffset)
203 throws ShortBufferException, IllegalBlockSizeException, BadPaddingException
204 {
205 if (output.length < this.getOutputSize(inputLen))
206 throw new ShortBufferException("The output buffer is too short");
207 byte [] t;
208 if (decrypt) {
209 if (input == null && !isBuffered) return 0;
210 if (input != null && inputLen < this.getPadSize(inputLen))
211 throw new BadPaddingException("Input data not bounded by the "+
212 "padding size");
213 int i = 0;
214 if (isBuffered) {
215 i = mode.update(scratchBuf, 0, blSize,
216 output, outputOffset);
217 if (input != null)
218 i += mode.update(input, inputOffset,
219 inputLen, output, outputOffset + blSize);
220 } else {
221 i = mode.update(input, inputOffset, inputLen,
222 output, outputOffset);
223 }
224 isBuffered = false;
225 return coreUnPad(output,i);
226 }
227 t = this.corePad(input, inputLen);
228 return mode.update(t, inputOffset, t.length, output, outputOffset);
229 }
230
231
232 protected int getBufSize() {
233 return mode.getBufSize();
234 }
235
236 // Abstract methods which the Padding classes must implement
237 abstract byte [] corePad(byte [] input, int inputLen)
238 throws IllegalBlockSizeException;
239
240 abstract int coreUnPad(byte [] input, int inputLen)
241 throws BadPaddingException;
242
243 abstract int getPadSize(int inputLen);
244 }