1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage org.bouncycastle.crypto.engines;
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.CipherParameters;
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.Digest;
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.InvalidCipherTextException;
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.Wrapper;
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.digests.SHA1Digest;
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.modes.CBCBlockCipher;
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.params.KeyParameter;
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.params.ParametersWithIV;
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Wrap keys according to
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-smime-key-wrap-01.txt">
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * draft-ietf-smime-key-wrap-01.txt</A>.
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <p>
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Note:
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <ul>
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <li>this is based on a draft, and as such is subject to change - don't use this class for anything requiring long term storage.
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <li>if you are using this to wrap triple-des keys you need to set the
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * parity bits on the key and, if it's a two-key triple-des key, pad it
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * yourself.
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * </ul>
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class DESedeWrapEngine
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    implements Wrapper
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   /** Field engine */
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   private CBCBlockCipher engine;
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   /** Field param */
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   private KeyParameter param;
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   /** Field paramPlusIV */
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   private ParametersWithIV paramPlusIV;
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   /** Field iv */
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   private byte[] iv;
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   /** Field forWrapping */
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   private boolean forWrapping;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   /** Field IV2           */
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   private static final byte[] IV2 = { (byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                       (byte) 0x2c, (byte) 0x79, (byte) 0xe8,
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                       (byte) 0x21, (byte) 0x05 };
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // checksum digest
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Digest  sha1 = new SHA1Digest();
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    byte[]  digest = new byte[20];
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   /**
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * Method init
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param forWrapping
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param param
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void init(boolean forWrapping, CipherParameters param)
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.forWrapping = forWrapping;
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.engine = new CBCBlockCipher(new DESedeEngine());
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (param instanceof KeyParameter)
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.param = (KeyParameter)param;
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (this.forWrapping)
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // Hm, we have no IV but we want to wrap ?!?
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // well, then we have to create our own IV.
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                this.iv = new byte[8];
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                SecureRandom sr = new SecureRandom();
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                sr.nextBytes(iv);
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else if (param instanceof ParametersWithIV)
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.paramPlusIV = (ParametersWithIV)param;
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.iv = this.paramPlusIV.getIV();
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.param = (KeyParameter)this.paramPlusIV.getParameters();
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (this.forWrapping)
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if ((this.iv == null) || (this.iv.length != 8))
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                {
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new IllegalArgumentException("IV is not 8 octets");
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            else
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new IllegalArgumentException(
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        "You should not supply an IV for unwrapping");
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   /**
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * Method getAlgorithmName
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @return the algorithm name "DESede".
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   public String getAlgorithmName()
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   {
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      return "DESede";
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   }
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   /**
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * Method wrap
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param in
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param inOff
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param inLen
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @return the wrapped bytes.
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   public byte[] wrap(byte[] in, int inOff, int inLen)
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   {
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (!forWrapping)
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      {
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         throw new IllegalStateException("Not initialized for wrapping");
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      byte keyToBeWrapped[] = new byte[inLen];
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      System.arraycopy(in, inOff, keyToBeWrapped, 0, inLen);
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      byte[] CKS = calculateCMSKeyChecksum(keyToBeWrapped);
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Let WKCKS = WK || CKS where || is concatenation.
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      byte[] WKCKS = new byte[keyToBeWrapped.length + CKS.length];
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      System.arraycopy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.length);
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      System.arraycopy(CKS, 0, WKCKS, keyToBeWrapped.length, CKS.length);
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Encrypt WKCKS in CBC mode using KEK as the key and IV as the
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // initialization vector. Call the results TEMP1.
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      byte TEMP1[] = new byte[WKCKS.length];
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      System.arraycopy(WKCKS, 0, TEMP1, 0, WKCKS.length);
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      int noOfBlocks = WKCKS.length / engine.getBlockSize();
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      int extraBytes = WKCKS.length % engine.getBlockSize();
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (extraBytes != 0)
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      {
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         throw new IllegalStateException("Not multiple of block length");
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      engine.init(true, paramPlusIV);
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (int i = 0; i < noOfBlocks; i++)
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      {
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         int currentBytePos = i * engine.getBlockSize();
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         engine.processBlock(TEMP1, currentBytePos, TEMP1, currentBytePos);
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Left TEMP2 = IV || TEMP1.
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      byte[] TEMP2 = new byte[this.iv.length + TEMP1.length];
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      System.arraycopy(this.iv, 0, TEMP2, 0, this.iv.length);
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      System.arraycopy(TEMP1, 0, TEMP2, this.iv.length, TEMP1.length);
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Reverse the order of the octets in TEMP2 and call the result TEMP3.
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      byte[] TEMP3 = new byte[TEMP2.length];
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (int i = 0; i < TEMP2.length; i++)
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      {
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         TEMP3[i] = TEMP2[TEMP2.length - (i + 1)];
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // result. It is 40 octets long if a 168 bit key is being wrapped.
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      this.engine.init(true, param2);
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (int i = 0; i < noOfBlocks + 1; i++)
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      {
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         int currentBytePos = i * engine.getBlockSize();
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         engine.processBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      return TEMP3;
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   }
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   /**
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * Method unwrap
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param in
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param inOff
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param inLen
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @return the unwrapped bytes.
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @throws InvalidCipherTextException
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public byte[] unwrap(byte[] in, int inOff, int inLen)
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project           throws InvalidCipherTextException
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (forWrapping)
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalStateException("Not set for unwrapping");
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (in == null)
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new InvalidCipherTextException("Null pointer as ciphertext");
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (inLen % engine.getBlockSize() != 0)
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new InvalidCipherTextException("Ciphertext not multiple of "
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    + engine.getBlockSize());
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      /*
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Check if the length of the cipher text is reasonable given the key
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // type. It must be 40 bytes for a 168 bit key and either 32, 40, or
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // or inconsistent with the algorithm for which the key is intended,
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // return error.
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      //
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // we do not accept 168 bit keys. it has to be 192 bit.
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      int lengthA = (estimatedKeyLengthInBit / 8) + 16;
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      int lengthB = estimatedKeyLengthInBit % 8;
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if ((lengthA != keyToBeUnwrapped.length) || (lengthB != 0)) {
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         throw new XMLSecurityException("empty");
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      */
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      this.engine.init(false, param2);
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      byte TEMP3[] = new byte[inLen];
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      System.arraycopy(in, inOff, TEMP3, 0, inLen);
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (int i = 0; i < (TEMP3.length / engine.getBlockSize()); i++)
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      {
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         int currentBytePos = i * engine.getBlockSize();
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         engine.processBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Reverse the order of the octets in TEMP3 and call the result TEMP2.
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      byte[] TEMP2 = new byte[TEMP3.length];
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (int i = 0; i < TEMP3.length; i++)
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      {
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         TEMP2[i] = TEMP3[TEMP3.length - (i + 1)];
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      this.iv = new byte[8];
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      byte[] TEMP1 = new byte[TEMP2.length - 8];
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      System.arraycopy(TEMP2, 0, this.iv, 0, 8);
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      System.arraycopy(TEMP2, 8, TEMP1, 0, TEMP2.length - 8);
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // found in the previous step. Call the result WKCKS.
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      this.engine.init(false, this.paramPlusIV);
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      byte[] WKCKS = new byte[TEMP1.length];
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      System.arraycopy(TEMP1, 0, WKCKS, 0, TEMP1.length);
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (int i = 0; i < (WKCKS.length / engine.getBlockSize()); i++)
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      {
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         int currentBytePos = i * engine.getBlockSize();
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         engine.processBlock(WKCKS, currentBytePos, WKCKS, currentBytePos);
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Decompose WKCKS. CKS is the last 8 octets and WK, the wrapped key, are
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // those octets before the CKS.
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      byte[] result = new byte[WKCKS.length - 8];
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      byte[] CKStoBeVerified = new byte[8];
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      System.arraycopy(WKCKS, 0, result, 0, WKCKS.length - 8);
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      System.arraycopy(WKCKS, WKCKS.length - 8, CKStoBeVerified, 0, 8);
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // with the CKS extracted in the above step. If they are not equal, return error.
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (!checkCMSKeyChecksum(result, CKStoBeVerified))
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      {
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         throw new InvalidCipherTextException(
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            "Checksum inside ciphertext is corrupted");
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // WK is the wrapped key, now extracted for use in data decryption.
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      return result;
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   }
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Some key wrap algorithms make use of the Key Checksum defined
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * in CMS [CMS-Algorithms]. This is used to provide an integrity
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * check value for the key being wrapped. The algorithm is
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * - Compute the 20 octet SHA-1 hash on the key being wrapped.
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * - Use the first 8 octets of this hash as the checksum value.
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param key
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the CMS checksum.
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws RuntimeException
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private byte[] calculateCMSKeyChecksum(
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] key)
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  result = new byte[8];
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sha1.update(key, 0, key.length);
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sha1.doFinal(digest, 0);
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(digest, 0, result, 0, 8);
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return result;
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param key
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param checksum
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return true if okay, false otherwise.
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean checkCMSKeyChecksum(
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] key,
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] checksum)
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] calculatedChecksum = calculateCMSKeyChecksum(key);
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (checksum.length != calculatedChecksum.length)
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i != checksum.length; i++)
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (checksum[i] != calculatedChecksum[i])
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return false;
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return true;
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
367