KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > services > jce > JCECipherProvider


1 /*
2
3    Derby - Class org.apache.derby.impl.services.jce.JCECipherProvider
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.services.jce;
23
24 import org.apache.derby.iapi.services.crypto.CipherFactory;
25 import org.apache.derby.iapi.services.crypto.CipherProvider;
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27
28 import org.apache.derby.iapi.error.StandardException;
29 import org.apache.derby.iapi.reference.SQLState;
30
31 import java.security.Key JavaDoc;
32 import java.security.InvalidKeyException JavaDoc;
33 import java.security.NoSuchAlgorithmException JavaDoc;
34 import java.security.GeneralSecurityException JavaDoc;
35 import java.security.NoSuchProviderException JavaDoc;
36
37 import javax.crypto.Cipher;
38 import javax.crypto.spec.IvParameterSpec;
39 import javax.crypto.SecretKeyFactory;
40 import javax.crypto.spec.SecretKeySpec;
41 import javax.crypto.SecretKey;
42
43
44 /**
45     This is a wrapper for a Cipher
46
47     @see CipherFactory
48  */

49 class JCECipherProvider implements CipherProvider
50 {
51     private Cipher cipher;
52     private int mode;
53     private boolean ivUsed = true;
54     private final IvParameterSpec ivspec;
55     private final int encryptionBlockSize;
56     private boolean sunjce; //default of bool is false
57

58     // other provider workaround, we need to re-init the cipher before every encrypt/decrypt
59
private SecretKey cryptixKey;
60
61     JCECipherProvider(int mode, SecretKey secretKey, byte[] iv, String JavaDoc algorithm, String JavaDoc provider)
62          throws StandardException
63     {
64         Throwable JavaDoc t;
65         ivspec = new IvParameterSpec(iv);
66         try
67         {
68
69
70             if (provider == null)
71             {
72                 cipher = Cipher.getInstance(algorithm);
73
74                 // see below.
75
if ("SunJCE".equals(cipher.getProvider().getName()))
76                     sunjce = true;
77             }
78             else
79             {
80                 /* The Sun encryption provider does not need to re-init the cipher
81                  * after each encrypt/decrypt. This is a speed up trick.
82                  * Other crypto providers needs this because the encrypt/decrypt
83                  * ciphers becomes out of sync after an encrypt/decrypt operation.
84                  */

85                 if( provider.equals("SunJCE") )
86                 {
87                     sunjce = true;
88                 }
89                 else
90                 {
91                     /* The BouncyCastle encryption provider is named "BC".
92                      * The full "BouncyCastleProvider" name used to work until
93                      * version 103 came out. (ie. Beta3 and Beta4 works fine)
94                      * This trick is so that Cipher.getInstance(algo, prov) will
95                      * not throw an exception. Resolve 3765.
96                      */

97                     if( provider.equals( "BouncyCastleProvider" ) )
98                         provider = "BC";
99                 }
100
101                 cipher = Cipher.getInstance(algorithm,provider);
102             }
103
104             // At creation time, the encryption block size is stored in order
105
// to do appropriate padding
106
encryptionBlockSize = cipher.getBlockSize();
107
108             this.mode = mode;
109             try {
110
111                 // ECB feedback mode does not require an IV
112
if (mode == CipherFactory.ENCRYPT)
113                 {
114                     if ((algorithm.indexOf("/ECB") > -1))
115                         cipher.init(Cipher.ENCRYPT_MODE, secretKey);
116                     else
117                         cipher.init(Cipher.ENCRYPT_MODE, secretKey,ivspec);
118                 }
119                 else if (mode == CipherFactory.DECRYPT)
120                 {
121                     if ((algorithm.indexOf("/ECB") > -1))
122                         cipher.init(Cipher.DECRYPT_MODE, secretKey);
123                     else
124                         cipher.init(Cipher.DECRYPT_MODE, secretKey,ivspec);
125                 }
126                 else
127                     throw StandardException.newException(SQLState.ILLEGAL_CIPHER_MODE);
128             } catch (InvalidKeyException JavaDoc ike) {
129
130                 if (algorithm.startsWith("DES")) {
131
132                     SecretKeyFactory skf;
133                     if (provider == null)
134                         skf = SecretKeyFactory.getInstance(secretKey.getAlgorithm());
135                     else
136                         skf = SecretKeyFactory.getInstance(secretKey.getAlgorithm(), provider);
137
138
139                     // Since the key may be a series of bytes generated by an arbitary means
140
// we need to translate it into a key suitable for the algorithm.
141
secretKey = skf.translateKey(new SecretKeySpec(secretKey.getEncoded(), secretKey.getAlgorithm()));
142
143                     // ECB mode does not require IV
144
if (mode == CipherFactory.ENCRYPT )
145                     {
146                         if ((algorithm.indexOf("/ECB") > -1))
147                             cipher.init(Cipher.ENCRYPT_MODE, secretKey);
148                         else
149                             cipher.init(Cipher.ENCRYPT_MODE, secretKey,ivspec);
150                     }
151                     else if (mode == CipherFactory.DECRYPT)
152                     {
153                         if ((algorithm.indexOf("/ECB") > -1))
154                             cipher.init(Cipher.DECRYPT_MODE, secretKey);
155                         else
156                             cipher.init(Cipher.DECRYPT_MODE, secretKey,ivspec);
157                     }
158
159                 }
160                 else
161                     throw StandardException.newException(SQLState.CRYPTO_EXCEPTION, ike);
162             }
163             cryptixKey = secretKey;
164
165             if (cipher.getIV() == null)
166                 ivUsed = false;
167
168             if (SanityManager.DEBUG)
169                 SanityManager.ASSERT(verifyIV(iv));
170
171             return;
172
173         }
174         catch (InvalidKeyException JavaDoc ike)
175         {
176             t = ike;
177         }
178         catch (NoSuchAlgorithmException JavaDoc nsae)
179         {
180             throw StandardException.newException(SQLState.ENCRYPTION_NOSUCH_ALGORITHM, algorithm, JCECipherFactory.providerErrorName(provider));
181         }
182         catch (NoSuchProviderException JavaDoc nspe)
183         {
184             throw StandardException.newException(SQLState.ENCRYPTION_BAD_PROVIDER, JCECipherFactory.providerErrorName(provider));
185         }
186         catch (GeneralSecurityException JavaDoc gse)
187         {
188             t = gse;
189         }
190         throw StandardException.newException(SQLState.CRYPTO_EXCEPTION, t);
191
192     }
193
194     /**
195         @see CipherProvider#encrypt
196
197         @exception StandardException Standard Cloudscape Error Policy
198      */

199     public int encrypt(byte[] cleartext, int offset, int length,
200                        byte[] ciphertext, int outputOffset)
201          throws StandardException
202     {
203         if (SanityManager.DEBUG)
204         {
205             SanityManager.ASSERT(mode == CipherFactory.ENCRYPT,
206                                  "calling encrypt on a decryption engine");
207             SanityManager.ASSERT(cleartext != null, "encrypting null cleartext");
208             SanityManager.ASSERT(offset >= 0, "offset < 0");
209             SanityManager.ASSERT(length > 0, "length <= 0");
210             SanityManager.ASSERT(offset+length <= cleartext.length,
211                                  "offset+length > cleartext.length");
212             SanityManager.ASSERT(length <= ciphertext.length-outputOffset,
213                                  "provided ciphertext buffer insufficient");
214         }
215
216         int retval = 0;
217         try
218         {
219             // this same cipher is shared across the entire raw store, make it
220
// MT safe
221
synchronized(this)
222             {
223                 if( !sunjce )
224                 {
225                     // this code is a workaround for other providers
226
try
227                     {
228                         //ivspec = new IvParameterSpec(cipher.getIV());
229
if (mode == CipherFactory.ENCRYPT)
230                         {
231                             if (ivUsed)
232                                 cipher.init(Cipher.ENCRYPT_MODE, cryptixKey, ivspec);
233                             else
234                                 cipher.init(Cipher.ENCRYPT_MODE,cryptixKey);
235                         }
236                         else if (mode == CipherFactory.DECRYPT)
237                         {
238                             if (ivUsed)
239                                 cipher.init(Cipher.DECRYPT_MODE, cryptixKey, ivspec);
240                             else
241                                 cipher.init(Cipher.DECRYPT_MODE, cryptixKey);
242                         }
243
244                     }
245                     catch (InvalidKeyException JavaDoc ike)
246                     {
247                         System.out.println("A " + ike);
248                         throw StandardException.newException(SQLState.CRYPTO_EXCEPTION, ike);
249                     }
250                 }
251
252                 retval = cipher.doFinal(cleartext, offset, length, ciphertext, outputOffset);
253             }
254         }
255         catch (IllegalStateException JavaDoc ise)
256         {
257             // should never happen
258
if (SanityManager.DEBUG)
259                 SanityManager.THROWASSERT("Illegal state exception");
260         }
261         catch (GeneralSecurityException JavaDoc gse)
262         {
263                         System.out.println("B " + gse);
264             throw StandardException.newException(SQLState.CRYPTO_EXCEPTION, gse);
265         }
266
267         if (SanityManager.DEBUG)
268             SanityManager.ASSERT(retval == length, "ciphertext length != length");
269
270         return retval;
271     }
272
273
274     /**
275         @see CipherProvider#decrypt
276
277         @exception StandardException Standard Cloudscape Error Policy
278      */

279     public int decrypt(byte[] ciphertext, int offset, int length,
280                        byte[] cleartext, int outputOffset)
281          throws StandardException
282     {
283         if (SanityManager.DEBUG)
284         {
285             SanityManager.ASSERT(mode == CipherFactory.DECRYPT,
286                                  "calling decrypt on a encryption engine");
287             SanityManager.ASSERT(ciphertext != null, "decrypting null ciphertext");
288             SanityManager.ASSERT(offset >= 0, "offset < 0");
289             SanityManager.ASSERT(length > 0, "length <= 0");
290             SanityManager.ASSERT(offset+length <= ciphertext.length,
291                                  "offset+length > ciphertext.length");
292             SanityManager.ASSERT(length <= cleartext.length-outputOffset,
293                                  "provided cleartexte buffer insufficient");
294         }
295
296         int retval = 0;
297         try
298         {
299             // this same cipher is shared across the entire raw store, make it
300
// MT safe
301
synchronized(this)
302             {
303                 if( !sunjce )
304                 {
305                     // this code is a workaround for other providers
306
try
307                     {
308                         //ivspec = new IvParameterSpec(cipher.getIV());
309

310                         if (mode == CipherFactory.ENCRYPT)
311                         {
312                             if (ivUsed)
313                                 cipher.init(Cipher.ENCRYPT_MODE, cryptixKey, ivspec);
314                             else
315                                 cipher.init(Cipher.ENCRYPT_MODE,cryptixKey);
316                         }
317                         else if (mode == CipherFactory.DECRYPT)
318                         {
319                             if (ivUsed)
320                                 cipher.init(Cipher.DECRYPT_MODE, cryptixKey, ivspec);
321                             else
322                                 cipher.init(Cipher.DECRYPT_MODE, cryptixKey);
323                         }
324
325                     }
326                     catch (InvalidKeyException JavaDoc ike)
327                     {
328                         System.out.println("C " + ike);
329                         throw StandardException.newException(SQLState.CRYPTO_EXCEPTION, ike);
330                     }
331
332                 }
333
334                 retval = cipher.doFinal(ciphertext, offset, length, cleartext, outputOffset);
335             }
336         }
337         catch (IllegalStateException JavaDoc ise)
338         {
339             // should never happen
340
if (SanityManager.DEBUG)
341                 SanityManager.THROWASSERT("Illegal state exception");
342         }
343         catch (GeneralSecurityException JavaDoc gse)
344         {
345                         System.out.println("D " + gse);
346             throw StandardException.newException(SQLState.CRYPTO_EXCEPTION, gse);
347         }
348
349         if (SanityManager.DEBUG)
350         {
351             SanityManager.ASSERT(retval == length,
352                                  "cleartext length != length");
353         }
354
355         return retval;
356     }
357
358     boolean verifyIV(byte[] IV)
359     {
360         byte[] myIV = cipher.getIV();
361         // null IV is OK only if IV is not used
362
if (myIV == null)
363             return !ivUsed;
364         if (myIV.length != IV.length)
365             return false;
366         for (int i = 0; i < IV.length; i++)
367             if (myIV[i] != IV[i])
368                 return false;
369         return true;
370     }
371
372     public int getEncryptionBlockSize()
373     {
374         return encryptionBlockSize;
375     }
376 }
377
Popular Tags