1 package org.bouncycastle.crypto.encodings;
2
3 import java.math.BigInteger;
4 import java.security.SecureRandom;
5
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;
11
12
16 public class PKCS1Encoding
17 implements AsymmetricBlockCipher
18 {
19 private static int HEADER_LENGTH = 10;
20
21 private SecureRandom random;
22 private AsymmetricBlockCipher engine;
23 private boolean forEncryption;
24 private boolean forPrivateKey;
25
26 public PKCS1Encoding(
27 AsymmetricBlockCipher cipher)
28 {
29 this.engine = cipher;
30 }
31
32 public AsymmetricBlockCipher getUnderlyingCipher()
33 {
34 return engine;
35 }
36
37 public void init(
38 boolean forEncryption,
39 CipherParameters param)
40 {
41 AsymmetricKeyParameter kParam;
42
43 if (param instanceof ParametersWithRandom)
44 {
45 ParametersWithRandom rParam = (ParametersWithRandom)param;
46
47 this.random = rParam.getRandom();
48 kParam = (AsymmetricKeyParameter)rParam.getParameters();
49 }
50 else
51 {
52 this.random = new SecureRandom();
53 kParam = (AsymmetricKeyParameter)param;
54 }
55
56 engine.init(forEncryption, kParam);
57
58 this.forPrivateKey = kParam.isPrivate();
59 this.forEncryption = forEncryption;
60 }
61
62 public int getInputBlockSize()
63 {
64 int baseBlockSize = engine.getInputBlockSize();
65
66 if (forEncryption)
67 {
68 return baseBlockSize - HEADER_LENGTH;
69 }
70 else
71 {
72 return baseBlockSize;
73 }
74 }
75
76 public int getOutputBlockSize()
77 {
78 int baseBlockSize = engine.getOutputBlockSize();
79
80 if (forEncryption)
81 {
82 return baseBlockSize;
83 }
84 else
85 {
86 return baseBlockSize - HEADER_LENGTH;
87 }
88 }
89
90 public byte[] processBlock(
91 byte[] in,
92 int inOff,
93 int inLen)
94 throws InvalidCipherTextException
95 {
96 if (forEncryption)
97 {
98 return encodeBlock(in, inOff, inLen);
99 }
100 else
101 {
102 return decodeBlock(in, inOff, inLen);
103 }
104 }
105
106 private byte[] encodeBlock(
107 byte[] in,
108 int inOff,
109 int inLen)
110 throws InvalidCipherTextException
111 {
112 byte[] block = new byte[engine.getInputBlockSize()];
113
114 if (forPrivateKey)
115 {
116 block[0] = 0x01;
117
118 for (int i = 1; i != block.length - inLen - 1; i++)
119 {
120 block[i] = (byte)0xFF;
121 }
122 }
123 else
124 {
125 random.nextBytes(block);
126
127 block[0] = 0x02;
128
129
130
131
132
133 for (int i = 1; i != block.length - inLen - 1; i++)
134 {
135 while (block[i] == 0)
136 {
137 block[i] = (byte)random.nextInt();
138 }
139 }
140 }
141
142 block[block.length - inLen - 1] = 0x00;
143 System.arraycopy(in, inOff, block, block.length - inLen, inLen);
144
145 return engine.processBlock(block, 0, block.length);
146 }
147
148
151 private byte[] decodeBlock(
152 byte[] in,
153 int inOff,
154 int inLen)
155 throws InvalidCipherTextException
156 {
157 byte[] block = engine.processBlock(in, inOff, inLen);
158
159 if (block.length < getOutputBlockSize())
160 {
161 throw new InvalidCipherTextException("block truncated");
162 }
163
164 if (block[0] != 1 && block[0] != 2)
165 {
166 throw new InvalidCipherTextException("unknown block type");
167 }
168
169
170
171
172 int start;
173
174 for (start = 1; start != block.length; start++)
175 {
176 if (block[start] == 0)
177 {
178 break;
179 }
180 }
181
182 start++;
183
184 if (start >= block.length || start < HEADER_LENGTH)
185 {
186 throw new InvalidCipherTextException("no data in block");
187 }
188
189 byte[] result = new byte[block.length - start];
190
191 System.arraycopy(block, start, result, 0, result.length);
192
193 return result;
194 }
195 }
196