001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the License). You may not use this file except in
005: * compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * Header Notice in each file and include the License file
014: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
015: * If applicable, add the following below the CDDL Header,
016: * with the fields enclosed by brackets [] replaced by
017: * you own identifying information:
018: * "Portions Copyrighted [year] [name of copyright owner]"
019: *
020: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
021: */
022:
023: package com.sun.xml.ws.security.opt.impl.enc;
024:
025: import com.sun.org.apache.xml.internal.security.algorithms.JCEMapper;
026: import com.sun.xml.wss.XWSSecurityException;
027: import com.sun.xml.wss.impl.c14n.StAXC14nCanonicalizerImpl;
028: import com.sun.xml.wss.impl.c14n.StAXEXC14nCanonicalizerImpl;
029: import com.sun.xml.wss.logging.LogDomainConstants;
030: import com.sun.xml.wss.logging.impl.opt.crypto.LogStringsMessages;
031:
032: import java.io.ByteArrayOutputStream;
033: import java.io.IOException;
034: import java.io.InputStream;
035: import java.security.InvalidAlgorithmParameterException;
036: import java.security.InvalidKeyException;
037: import java.security.NoSuchAlgorithmException;
038: import java.util.Iterator;
039: import java.util.logging.Level;
040: import java.util.logging.Logger;
041:
042: import javax.crypto.NoSuchPaddingException;
043: import javax.crypto.spec.IvParameterSpec;
044: import com.sun.xml.ws.security.opt.crypto.JAXBData;
045: import com.sun.xml.ws.security.opt.crypto.StreamWriterData;
046: import com.sun.xml.ws.security.opt.impl.util.OutputStreamWrapper;
047: import java.io.OutputStream;
048: import java.security.Key;
049: import javax.crypto.CipherOutputStream;
050: import javax.crypto.Cipher;
051: import javax.xml.crypto.Data;
052: import javax.crypto.CipherInputStream;
053: import javax.xml.stream.XMLStreamException;
054: import org.jvnet.staxex.NamespaceContextEx;
055: import org.jvnet.staxex.NamespaceContextEx.Binding;
056: import com.sun.xml.wss.impl.XWSSecurityRuntimeException;
057:
058: /**
059: * @author K.Venugopal@sun.com
060: * @author Abhijit.Das@Sun.COM
061: */
062: //TODO : Venu refactor this code after FCS.
063: public class CryptoProcessor {
064: private static final Logger logger = Logger.getLogger(
065: LogDomainConstants.IMPL_OPT_CRYPTO_DOMAIN,
066: LogDomainConstants.IMPL_OPT_CRYPTO_DOMAIN_BUNDLE);
067:
068: protected Cipher cipher = null;
069: protected Key key = null;
070: protected Data data = null;
071: private int mode = Cipher.ENCRYPT_MODE;
072: private String algorithm = "";
073: private Key dk = null;
074: private byte[] ed = null;
075: private IvParameterSpec ivSpec = null;
076: private byte[] encryptedDataCV = null;
077:
078: public CryptoProcessor() {
079: }
080:
081: /** Creates a new instance of EncryptionProcessor */
082: public CryptoProcessor(int mode, String algo, Data ed, Key key)
083: throws XWSSecurityException {
084: this .mode = mode;
085: this .algorithm = algo;
086: this .data = ed;
087: this .key = key;
088: }
089:
090: public CryptoProcessor(int mode, String algo, Key dk, Key key)
091: throws XWSSecurityException {
092: this .mode = mode;
093: this .algorithm = algo;
094: this .key = key;
095: this .dk = dk;
096: }
097:
098: public CryptoProcessor(int mode, String algo, Key key)
099: throws XWSSecurityException {
100: this .mode = mode;
101: this .algorithm = algo;
102: this .key = key;
103: }
104:
105: protected void initCipher() throws NoSuchAlgorithmException,
106: NoSuchPaddingException, InvalidKeyException {
107: if (cipher == null) {
108: String transformation = convertAlgURIToTransformation(getAlgorithm());
109: cipher = Cipher.getInstance(transformation);
110: cipher.init(mode, getKey());
111: }
112: }
113:
114: protected String getAlgorithm() {
115: return algorithm;
116: }
117:
118: /**
119: * Convert algorithm URI to actual transformation (DES/CBC/PKCS5Padding)
120: *
121: * @param algorithmURI
122: * @return String representing transforms
123: */
124: protected String convertAlgURIToTransformation(String algorithmURI) {
125: return JCEMapper.translateURItoJCEID(algorithmURI);
126: }
127:
128: protected Key getKey() {
129: return key;
130: }
131:
132: public void encrypt(OutputStream outputStream) throws IOException {
133: if (mode == Cipher.ENCRYPT_MODE) {
134: encryptData(outputStream);
135: } else if (mode == cipher.WRAP_MODE) {
136: encryptKey(outputStream);
137: }
138: }
139:
140: public byte[] getCipherValueOfEK() {
141: try {
142: if (ed == null) {
143: if (cipher == null) {
144: initCipher();
145: }
146: ed = cipher.wrap(dk);
147: }
148: } catch (NoSuchAlgorithmException ex) {
149: logger
150: .log(
151: Level.SEVERE,
152: LogStringsMessages
153: .WSS_1904_UNSUPPORTED_KEYENCRYPTION_ALGORITHM(getAlgorithm()),
154: ex);
155: throw new XWSSecurityRuntimeException(ex);
156: } catch (javax.crypto.NoSuchPaddingException ex) {
157: logger.log(Level.SEVERE, LogStringsMessages
158: .WSS_1905_ERROR_INITIALIZING_CIPHER(), ex);
159: throw new XWSSecurityRuntimeException(ex);
160: } catch (InvalidKeyException ex) {
161: logger.log(Level.SEVERE, LogStringsMessages
162: .WSS_1906_INVALID_KEY_ERROR(), ex);
163: throw new XWSSecurityRuntimeException(ex);
164: } catch (javax.crypto.IllegalBlockSizeException ibe) {
165: logger.log(Level.SEVERE, LogStringsMessages
166: .WSS_1907_INCORRECT_BLOCK_SIZE(), ibe);
167: throw new XWSSecurityRuntimeException(ibe);
168: }
169: return ed;
170: }
171:
172: public void encryptKey(OutputStream outputStream)
173: throws IOException {
174: try {
175: if (ed == null) {
176: if (cipher == null) {
177: initCipher();
178: }
179: ed = cipher.wrap(dk);
180: //String data = com.sun.org.apache.xml.internal.security.utils.Base64.encode(ed);
181: }
182: outputStream.write(ed);
183: outputStream.flush();
184:
185: } catch (NoSuchAlgorithmException ex) {
186: logger
187: .log(
188: Level.SEVERE,
189: LogStringsMessages
190: .WSS_1904_UNSUPPORTED_KEYENCRYPTION_ALGORITHM(getAlgorithm()),
191: ex);
192: throw new XWSSecurityRuntimeException(
193: "Unable to compute CipherValue as "
194: + getAlgorithm() + " is not supported", ex);
195: } catch (javax.crypto.NoSuchPaddingException ex) {
196: logger.log(Level.SEVERE, LogStringsMessages
197: .WSS_1905_ERROR_INITIALIZING_CIPHER(), ex);
198: throw new XWSSecurityRuntimeException(
199: "Error occurred while initializing the Cipher", ex);
200: } catch (InvalidKeyException ex) {
201: logger.log(Level.SEVERE, LogStringsMessages
202: .WSS_1906_INVALID_KEY_ERROR(), ex);
203: throw new XWSSecurityRuntimeException(
204: "Unable to calculate cipher value as invalid key was provided",
205: ex);
206: } catch (javax.crypto.IllegalBlockSizeException ibe) {
207: logger.log(Level.SEVERE, LogStringsMessages
208: .WSS_1907_INCORRECT_BLOCK_SIZE(), ibe);
209: throw new XWSSecurityRuntimeException(ibe);
210: }
211: }
212:
213: public void setEncryptedDataCV(byte[] cv) {
214: encryptedDataCV = cv;
215: }
216:
217: public void encryptData(OutputStream eos) throws IOException {
218: try {
219: OutputStreamWrapper outputStream = new OutputStreamWrapper(
220: eos);
221: if (encryptedDataCV != null) {
222: outputStream.write(encryptedDataCV);
223: return;
224: }
225: // Thread.dumpStack();
226: if (cipher == null) {
227: initCipher();
228: }
229: //Base64OutputStream bos = new Base64OutputStream(outputStream);
230: //TODO :: Wrap outputstream with base64 encoder
231: CipherOutputStream cos = new CipherOutputStream(
232: outputStream, cipher);
233: //BufferedStreamWriter bsw = new BufferedStreamWriter(cos);
234: byte[] iv = cipher.getIV();
235: outputStream.write(iv);
236: outputStream.flush();
237: if (data instanceof JAXBData) {
238: ((JAXBData) data).writeTo(cos);// write in chucks
239: } else if (data instanceof StreamWriterData) {
240: StAXC14nCanonicalizerImpl exc14n = new StAXEXC14nCanonicalizerImpl();
241: NamespaceContextEx nsEx = ((StreamWriterData) data)
242: .getNamespaceContext();
243: Iterator<Binding> iter = nsEx.iterator();
244: while (iter.hasNext()) {
245: Binding binding = iter.next();
246: exc14n.writeNamespace(binding.getPrefix(), binding
247: .getNamespaceURI());
248: }
249: if (logger.isLoggable(Level.FINEST)) {
250: exc14n.setStream(new ByteArrayOutputStream());
251: } else {
252: exc14n.setStream(cos);
253: }
254: try {
255: ((StreamWriterData) data).write(exc14n);
256: if (logger.isLoggable(Level.FINEST)) {
257: byte[] cd = ((ByteArrayOutputStream) exc14n
258: .getOutputStream()).toByteArray();
259: logger
260: .log(
261: Level.FINEST,
262: LogStringsMessages
263: .WSS_1951_ENCRYPTED_DATA_VALUE(new String(
264: cd)));
265: cos.write(cd);
266: }
267: } catch (javax.xml.stream.XMLStreamException ex) {
268: logger.log(Level.SEVERE, LogStringsMessages
269: .WSS_1908_ERROR_WRITING_ENCRYPTEDDATA());
270: }
271: }
272:
273: cos.flush();
274: cos.close();
275: } catch (NoSuchAlgorithmException ex) {
276: logger
277: .log(
278: Level.SEVERE,
279: LogStringsMessages
280: .WSS_1909_UNSUPPORTED_DATAENCRYPTION_ALGORITHM(getAlgorithm()),
281: ex);
282: throw new XWSSecurityRuntimeException(
283: "Unable to compute CipherValue as "
284: + getAlgorithm() + " is not supported", ex);
285: } catch (javax.crypto.NoSuchPaddingException ex) {
286: logger.log(Level.SEVERE, LogStringsMessages
287: .WSS_1905_ERROR_INITIALIZING_CIPHER(), ex);
288: throw new XWSSecurityRuntimeException(
289: "Error occurred while initializing the Cipher", ex);
290: } catch (InvalidKeyException ex) {
291: logger.log(Level.SEVERE, LogStringsMessages
292: .WSS_1906_INVALID_KEY_ERROR(), ex);
293: throw new XWSSecurityRuntimeException(
294: "Unable to calculate cipher value as invalid key was provided",
295: ex);
296: } catch (XMLStreamException xse) {
297: logger
298: .log(
299: Level.SEVERE,
300: LogStringsMessages
301: .WSS_1910_ERROR_WRITING_NAMESPACES_CANONICALIZER(xse
302: .getMessage()), xse);
303: throw new XWSSecurityRuntimeException(
304: "Unable to write namespaces to exclusive canonicalizer",
305: xse);
306: } catch (com.sun.xml.wss.XWSSecurityException ex) {
307: logger.log(Level.SEVERE,
308: LogStringsMessages
309: .WSS_1911_ERROR_WRITING_CIPHERVALUE(ex
310: .getMessage()), ex);
311: throw new XWSSecurityRuntimeException(
312: "Unable to calculate cipher value ", ex);
313: }
314: }
315:
316: public Key decryptKey(byte[] encryptedKey, String encAlgo)
317: throws IOException {
318:
319: try {
320: if (mode == Cipher.UNWRAP_MODE) {
321: if (algorithm == null || algorithm.length() == 0) {
322: logger.log(Level.SEVERE, LogStringsMessages
323: .WSS_1912_DECRYPTION_ALGORITHM_NULL());
324: throw new IOException(
325: "Cannot decrypt a key without knowing the algorithm");
326: }
327:
328: if (key == null) {
329: logger.log(Level.SEVERE, LogStringsMessages
330: .WSS_1913_DECRYPTION_KEY_NULL());
331: throw new IOException(
332: "Key used to decrypt EncryptedKey cannot be null");
333: }
334: if (cipher == null) {
335: initCipher();
336: }
337: return cipher.unwrap(encryptedKey, JCEMapper
338: .getJCEKeyAlgorithmFromURI(encAlgo),
339: Cipher.SECRET_KEY);
340:
341: }
342: } catch (InvalidKeyException ex) {
343: logger.log(Level.SEVERE, LogStringsMessages
344: .WSS_1906_INVALID_KEY_ERROR(), ex);
345: throw new XWSSecurityRuntimeException(ex);
346: } catch (NoSuchAlgorithmException ex) {
347: logger
348: .log(
349: Level.SEVERE,
350: LogStringsMessages
351: .WSS_1904_UNSUPPORTED_KEYENCRYPTION_ALGORITHM(algorithm),
352: ex);
353: throw new XWSSecurityRuntimeException(ex);
354: } catch (javax.crypto.NoSuchPaddingException ex) {
355: logger.log(Level.SEVERE, LogStringsMessages
356: .WSS_1905_ERROR_INITIALIZING_CIPHER(), ex);
357: throw new XWSSecurityRuntimeException(ex);
358: }
359: logger.log(Level.SEVERE, LogStringsMessages
360: .WSS_1914_INVALID_CIPHER_MODE(mode));
361: throw new IOException("Invalid Cipher mode:" + mode);
362: }
363:
364: public InputStream decryptData(InputStream is) throws IOException {
365: try {
366: if (mode == Cipher.DECRYPT_MODE) {
367: if (cipher == null) {
368: String transformation = convertAlgURIToTransformation(getAlgorithm());
369: cipher = Cipher.getInstance(transformation);
370: int len = cipher.getBlockSize();
371: byte[] iv = new byte[len];
372: is.read(iv, 0, len);
373: ivSpec = new IvParameterSpec(iv);
374: cipher.init(mode, key, ivSpec);
375: }
376: return new CipherInputStream(is, cipher);
377: } else {
378: logger.log(Level.SEVERE, LogStringsMessages
379: .WSS_1914_INVALID_CIPHER_MODE(mode));
380: throw new IOException("Invalid Cipher mode:" + mode);
381: }
382:
383: } catch (InvalidKeyException ex) {
384: logger.log(Level.SEVERE, LogStringsMessages
385: .WSS_1906_INVALID_KEY_ERROR(), ex);
386: throw new XWSSecurityRuntimeException(ex);
387: } catch (NoSuchAlgorithmException ex) {
388: logger
389: .log(
390: Level.SEVERE,
391: LogStringsMessages
392: .WSS_1909_UNSUPPORTED_DATAENCRYPTION_ALGORITHM(getAlgorithm()),
393: ex);
394: throw new XWSSecurityRuntimeException(ex);
395: } catch (javax.crypto.NoSuchPaddingException ex) {
396: logger.log(Level.SEVERE, LogStringsMessages
397: .WSS_1905_ERROR_INITIALIZING_CIPHER(), ex);
398: throw new XWSSecurityRuntimeException(ex);
399: } catch (InvalidAlgorithmParameterException invalidAPE) {
400: logger
401: .log(
402: Level.SEVERE,
403: LogStringsMessages
404: .WSS_1915_INVALID_ALGORITHM_PARAMETERS(getAlgorithm()),
405: invalidAPE);
406: throw new XWSSecurityRuntimeException(invalidAPE);
407: }
408:
409: }
410: }
|