1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage org.bouncycastle.crypto.encodings;
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.SecureRandom;
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.AsymmetricBlockCipher;
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.CipherParameters;
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.Digest;
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.InvalidCipherTextException;
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.digests.SHA1Digest;
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.params.AsymmetricKeyParameter;
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.params.ParametersWithRandom;
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class OAEPEncoding
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    implements AsymmetricBlockCipher
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private byte[]                  defHash;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private Digest                  hash;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private AsymmetricBlockCipher   engine;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private SecureRandom            random;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean                 forEncryption;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public OAEPEncoding(
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        AsymmetricBlockCipher   cipher)
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this(cipher, new SHA1Digest(), null);
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public OAEPEncoding(
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        AsymmetricBlockCipher       cipher,
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Digest                      hash)
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this(cipher, hash, null);
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public OAEPEncoding(
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        AsymmetricBlockCipher       cipher,
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Digest                      hash,
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]                      encodingParams)
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.engine = cipher;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.hash = hash;
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.defHash = new byte[hash.getDigestSize()];
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (encodingParams != null)
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hash.update(encodingParams, 0, encodingParams.length);
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        hash.doFinal(defHash, 0);
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public AsymmetricBlockCipher getUnderlyingCipher()
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return engine;
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void init(
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean             forEncryption,
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        CipherParameters    param)
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        AsymmetricKeyParameter  kParam;
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (param instanceof ParametersWithRandom)
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ParametersWithRandom  rParam = (ParametersWithRandom)param;
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.random = rParam.getRandom();
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            kParam = (AsymmetricKeyParameter)rParam.getParameters();
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.random = new SecureRandom();
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            kParam = (AsymmetricKeyParameter)param;
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        engine.init(forEncryption, kParam);
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.forEncryption = forEncryption;
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int getInputBlockSize()
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     baseBlockSize = engine.getInputBlockSize();
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (forEncryption)
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return baseBlockSize - 1 - 2 * defHash.length;
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return baseBlockSize;
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int getOutputBlockSize()
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     baseBlockSize = engine.getOutputBlockSize();
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (forEncryption)
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return baseBlockSize;
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return baseBlockSize - 1 - 2 * defHash.length;
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public byte[] processBlock(
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  in,
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     inOff,
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     inLen)
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws InvalidCipherTextException
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (forEncryption)
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return encodeBlock(in, inOff, inLen);
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return decodeBlock(in, inOff, inLen);
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public byte[] encodeBlock(
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  in,
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     inOff,
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     inLen)
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws InvalidCipherTextException
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  block = new byte[getInputBlockSize() + 1 + 2 * defHash.length];
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // copy in the message
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(in, inOff, block, block.length - inLen, inLen);
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // add sentinel
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        block[block.length - inLen - 1] = 0x01;
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0)
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // add the hash of the encoding params.
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(defHash, 0, block, defHash.length, defHash.length);
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // generate the seed.
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  seed = new byte[defHash.length];
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        random.nextBytes(seed);
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // mask the message block.
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  mask = maskGeneratorFunction1(seed, 0, seed.length, block.length - defHash.length);
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = defHash.length; i != block.length; i++)
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            block[i] ^= mask[i - defHash.length];
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // add in the seed
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(seed, 0, block, 0, defHash.length);
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // mask the seed.
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        mask = maskGeneratorFunction1(
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        block, defHash.length, block.length - defHash.length, defHash.length);
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i != defHash.length; i++)
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            block[i] ^= mask[i];
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return engine.processBlock(block, 0, block.length);
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception InvalidCipherTextException if the decrypted block turns out to
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * be badly formatted.
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public byte[] decodeBlock(
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  in,
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     inOff,
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     inLen)
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws InvalidCipherTextException
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  data = engine.processBlock(in, inOff, inLen);
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  block = null;
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // as we may have zeros in our leading bytes for the block we produced
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // on encryption, we need to make sure our decrypted block comes back
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // the same size.
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (data.length < engine.getOutputBlockSize())
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            block = new byte[engine.getOutputBlockSize()];
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.arraycopy(data, 0, block, block.length - data.length, data.length);
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            block = data;
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (block.length < (2 * defHash.length) + 1)
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new InvalidCipherTextException("data too short");
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // unmask the seed.
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] mask = maskGeneratorFunction1(
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    block, defHash.length, block.length - defHash.length, defHash.length);
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i != defHash.length; i++)
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            block[i] ^= mask[i];
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // unmask the message block.
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        mask = maskGeneratorFunction1(block, 0, defHash.length, block.length - defHash.length);
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = defHash.length; i != block.length; i++)
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            block[i] ^= mask[i - defHash.length];
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // check the hash of the encoding params.
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i != defHash.length; i++)
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (defHash[i] != block[defHash.length + i])
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new InvalidCipherTextException("data hash wrong");
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // find the data block
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int start;
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (start = 2 * defHash.length; start != block.length; start++)
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (block[start] == 1 || block[start] != 0)
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (start >= (block.length - 1) || block[start] != 1)
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new InvalidCipherTextException("data start wrong " + start);
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        start++;
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // extract the data block
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  output = new byte[block.length - start];
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(block, start, output, 0, output.length);
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return output;
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * int to octet string.
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void ItoOSP(
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     i,
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  sp)
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sp[0] = (byte)(i >>> 24);
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sp[1] = (byte)(i >>> 16);
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sp[2] = (byte)(i >>> 8);
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sp[3] = (byte)(i >>> 0);
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * mask generator function, as described in PKCS1v2.
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private byte[] maskGeneratorFunction1(
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  Z,
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     zOff,
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     zLen,
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     length)
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  mask = new byte[length];
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  hashBuf = new byte[defHash.length];
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  C = new byte[4];
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     counter = 0;
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        hash.reset();
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        do
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ItoOSP(counter, C);
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hash.update(Z, zOff, zLen);
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hash.update(C, 0, C.length);
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hash.doFinal(hashBuf, 0);
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.arraycopy(hashBuf, 0, mask, counter * defHash.length, defHash.length);
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        while (++counter < (length / defHash.length));
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((counter * defHash.length) < length)
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ItoOSP(counter, C);
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hash.update(Z, zOff, zLen);
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hash.update(C, 0, C.length);
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hash.doFinal(hashBuf, 0);
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.arraycopy(hashBuf, 0, mask, counter * defHash.length, mask.length - (counter * defHash.length));
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return mask;
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
343