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