1 package org.bouncycastle.crypto.encodings;
3 import java.math.BigInteger;
4 import java.security.SecureRandom;
6 import org.bouncycastle.crypto.CipherParameters;
7 import org.bouncycastle.crypto.AsymmetricBlockCipher;
8 import org.bouncycastle.crypto.InvalidCipherTextException;
9 import org.bouncycastle.crypto.params.ParametersWithRandom;
10 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
13 * this does your basic PKCS 1 v1.5 padding - whether or not you should be using this
14 * depends on your application - see PKCS1 Version 2 for details.
16 public class PKCS1Encoding
17 implements AsymmetricBlockCipher
19 private static int HEADER_LENGTH = 10;
21 private SecureRandom random;
22 private AsymmetricBlockCipher engine;
23 private boolean forEncryption;
24 private boolean forPrivateKey;
27 AsymmetricBlockCipher cipher)
32 public AsymmetricBlockCipher getUnderlyingCipher()
38 boolean forEncryption,
39 CipherParameters param)
41 AsymmetricKeyParameter kParam;
43 if (param instanceof ParametersWithRandom)
45 ParametersWithRandom rParam = (ParametersWithRandom)param;
47 this.random = rParam.getRandom();
48 kParam = (AsymmetricKeyParameter)rParam.getParameters();
52 this.random = new SecureRandom();
53 kParam = (AsymmetricKeyParameter)param;
56 engine.init(forEncryption, kParam);
58 this.forPrivateKey = kParam.isPrivate();
59 this.forEncryption = forEncryption;
62 public int getInputBlockSize()
64 int baseBlockSize = engine.getInputBlockSize();
68 return baseBlockSize - HEADER_LENGTH;
76 public int getOutputBlockSize()
78 int baseBlockSize = engine.getOutputBlockSize();
86 return baseBlockSize - HEADER_LENGTH;
90 public byte[] processBlock(
94 throws InvalidCipherTextException
98 return encodeBlock(in, inOff, inLen);
102 return decodeBlock(in, inOff, inLen);
106 private byte[] encodeBlock(
110 throws InvalidCipherTextException
112 byte[] block = new byte[engine.getInputBlockSize()];
116 block[0] = 0x01; // type code 1
118 for (int i = 1; i != block.length - inLen - 1; i++)
120 block[i] = (byte)0xFF;
125 random.nextBytes(block); // random fill
127 block[0] = 0x02; // type code 2
130 // a zero byte marks the end of the padding, so all
131 // the pad bytes must be non-zero.
133 for (int i = 1; i != block.length - inLen - 1; i++)
135 while (block[i] == 0)
137 block[i] = (byte)random.nextInt();
142 block[block.length - inLen - 1] = 0x00; // mark the end of the padding
143 System.arraycopy(in, inOff, block, block.length - inLen, inLen);
145 return engine.processBlock(block, 0, block.length);
149 * @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format.
151 private byte[] decodeBlock(
155 throws InvalidCipherTextException
157 byte[] block = engine.processBlock(in, inOff, inLen);
159 if (block.length < getOutputBlockSize())
161 throw new InvalidCipherTextException("block truncated");
164 if (block[0] != 1 && block[0] != 2)
166 throw new InvalidCipherTextException("unknown block type");
170 // find and extract the message block.
174 for (start = 1; start != block.length; start++)
176 if (block[start] == 0)
182 start++; // data should start at the next byte
184 if (start >= block.length || start < HEADER_LENGTH)
186 throw new InvalidCipherTextException("no data in block");
189 byte[] result = new byte[block.length - start];
191 System.arraycopy(block, start, result, 0, result.length);