/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the license at
* https://glassfish.dev.java.net/public/CDDLv1.0.html.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at https://glassfish.dev.java.net/public/CDDLv1.0.html.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* you own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Copyright 2006 Sun Microsystems Inc. All Rights Reserved
*/
package com.sun.xml.ws.security.opt.impl.enc;
import com.sun.org.apache.xml.internal.security.algorithms.JCEMapper;
import com.sun.xml.wss.XWSSecurityException;
import com.sun.xml.wss.impl.c14n.StAXC14nCanonicalizerImpl;
import com.sun.xml.wss.impl.c14n.StAXEXC14nCanonicalizerImpl;
import com.sun.xml.wss.logging.LogDomainConstants;
import com.sun.xml.wss.logging.impl.opt.crypto.LogStringsMessages;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import com.sun.xml.ws.security.opt.crypto.JAXBData;
import com.sun.xml.ws.security.opt.crypto.StreamWriterData;
import com.sun.xml.ws.security.opt.impl.util.OutputStreamWrapper;
import java.io.OutputStream;
import java.security.Key;
import javax.crypto.CipherOutputStream;
import javax.crypto.Cipher;
import javax.xml.crypto.Data;
import javax.crypto.CipherInputStream;
import javax.xml.stream.XMLStreamException;
import org.jvnet.staxex.NamespaceContextEx;
import org.jvnet.staxex.NamespaceContextEx.Binding;
import com.sun.xml.wss.impl.XWSSecurityRuntimeException;
/**
* @author K.Venugopal@sun.com
* @author Abhijit.Das@Sun.COM
*/
//TODO : Venu refactor this code after FCS.
public class CryptoProcessor {
private static final Logger logger = Logger.getLogger(LogDomainConstants.IMPL_OPT_CRYPTO_DOMAIN,
LogDomainConstants.IMPL_OPT_CRYPTO_DOMAIN_BUNDLE);
protected Cipher cipher = null;
protected Key key = null;
protected Data data = null;
private int mode = Cipher.ENCRYPT_MODE;
private String algorithm = "";
private Key dk = null;
private byte[] ed = null;
private IvParameterSpec ivSpec = null;
private byte[] encryptedDataCV = null;
public CryptoProcessor(){}
/** Creates a new instance of EncryptionProcessor */
public CryptoProcessor(int mode,String algo,Data ed,Key key) throws XWSSecurityException{
this.mode = mode;
this.algorithm = algo;
this.data = ed;
this.key = key;
}
public CryptoProcessor(int mode,String algo,Key dk,Key key) throws XWSSecurityException{
this.mode = mode;
this.algorithm = algo;
this.key = key;
this.dk = dk;
}
public CryptoProcessor(int mode,String algo,Key key) throws XWSSecurityException{
this.mode = mode;
this.algorithm = algo;
this.key = key;
}
protected void initCipher() throws NoSuchAlgorithmException,NoSuchPaddingException, InvalidKeyException{
if ( cipher == null ) {
String transformation = convertAlgURIToTransformation(getAlgorithm());
cipher = Cipher.getInstance(transformation);
cipher.init(mode, getKey());
}
}
protected String getAlgorithm(){
return algorithm;
}
/**
* Convert algorithm URI to actual transformation (DES/CBC/PKCS5Padding)
*
* @param algorithmURI
* @return String representing transforms
*/
protected String convertAlgURIToTransformation(String algorithmURI) {
return JCEMapper.translateURItoJCEID(algorithmURI);
}
protected Key getKey(){
return key;
}
public void encrypt(OutputStream outputStream) throws IOException{
if(mode == Cipher.ENCRYPT_MODE){
encryptData(outputStream);
}else if(mode == cipher.WRAP_MODE){
encryptKey(outputStream);
}
}
public byte[] getCipherValueOfEK(){
try{
if(ed == null){
if(cipher == null){
initCipher();
}
ed = cipher.wrap(dk);
}
} catch (NoSuchAlgorithmException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1904_UNSUPPORTED_KEYENCRYPTION_ALGORITHM(getAlgorithm()), ex);
throw new XWSSecurityRuntimeException(ex);
} catch (javax.crypto.NoSuchPaddingException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1905_ERROR_INITIALIZING_CIPHER(), ex);
throw new XWSSecurityRuntimeException(ex);
} catch (InvalidKeyException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1906_INVALID_KEY_ERROR(), ex);
throw new XWSSecurityRuntimeException(ex);
} catch(javax.crypto.IllegalBlockSizeException ibe){
logger.log(Level.SEVERE, LogStringsMessages.WSS_1907_INCORRECT_BLOCK_SIZE(), ibe);
throw new XWSSecurityRuntimeException(ibe);
}
return ed;
}
public void encryptKey(OutputStream outputStream)throws IOException{
try{
if(ed == null){
if(cipher == null){
initCipher();
}
ed = cipher.wrap(dk);
//String data = com.sun.org.apache.xml.internal.security.utils.Base64.encode(ed);
}
outputStream.write(ed);
outputStream.flush();
} catch (NoSuchAlgorithmException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1904_UNSUPPORTED_KEYENCRYPTION_ALGORITHM(getAlgorithm()), ex);
throw new XWSSecurityRuntimeException("Unable to compute CipherValue as "+getAlgorithm()+" is not supported", ex);
} catch (javax.crypto.NoSuchPaddingException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1905_ERROR_INITIALIZING_CIPHER(), ex);
throw new XWSSecurityRuntimeException("Error occurred while initializing the Cipher", ex);
} catch (InvalidKeyException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1906_INVALID_KEY_ERROR(), ex);
throw new XWSSecurityRuntimeException("Unable to calculate cipher value as invalid key was provided",ex);
}catch(javax.crypto.IllegalBlockSizeException ibe){
logger.log(Level.SEVERE, LogStringsMessages.WSS_1907_INCORRECT_BLOCK_SIZE(), ibe);
throw new XWSSecurityRuntimeException(ibe);
}
}
public void setEncryptedDataCV(byte [] cv){
encryptedDataCV = cv;
}
public void encryptData(OutputStream eos) throws IOException{
try{
OutputStreamWrapper outputStream = new OutputStreamWrapper(eos);
if(encryptedDataCV != null){
outputStream.write(encryptedDataCV);
return;
}
// Thread.dumpStack();
if(cipher == null){
initCipher();
}
//Base64OutputStream bos = new Base64OutputStream(outputStream);
//TODO :: Wrap outputstream with base64 encoder
CipherOutputStream cos = new CipherOutputStream(outputStream,cipher);
//BufferedStreamWriter bsw = new BufferedStreamWriter(cos);
byte [] iv = cipher.getIV();
outputStream.write(iv);
outputStream.flush();
if(data instanceof JAXBData){
((JAXBData)data).writeTo(cos);// write in chucks
}else if(data instanceof StreamWriterData){
StAXC14nCanonicalizerImpl exc14n = new StAXEXC14nCanonicalizerImpl();
NamespaceContextEx nsEx = ((StreamWriterData)data).getNamespaceContext();
Iterator<Binding> iter = nsEx.iterator();
while(iter.hasNext()){
Binding binding = iter.next();
exc14n.writeNamespace(binding.getPrefix(),binding.getNamespaceURI());
}
if(logger.isLoggable(Level.FINEST)){
exc14n.setStream(new ByteArrayOutputStream());
}else{
exc14n.setStream(cos);
}
try {
((StreamWriterData)data).write(exc14n);
if(logger.isLoggable(Level.FINEST)){
byte [] cd=((ByteArrayOutputStream)exc14n.getOutputStream()).toByteArray();
logger.log(Level.FINEST, LogStringsMessages.WSS_1951_ENCRYPTED_DATA_VALUE(new String(cd)));
cos.write(cd);
}
} catch (javax.xml.stream.XMLStreamException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1908_ERROR_WRITING_ENCRYPTEDDATA());
}
}
cos.flush();
cos.close();
} catch (NoSuchAlgorithmException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1909_UNSUPPORTED_DATAENCRYPTION_ALGORITHM(getAlgorithm()), ex);
throw new XWSSecurityRuntimeException("Unable to compute CipherValue as "+getAlgorithm()+" is not supported", ex);
} catch (javax.crypto.NoSuchPaddingException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1905_ERROR_INITIALIZING_CIPHER(), ex);
throw new XWSSecurityRuntimeException("Error occurred while initializing the Cipher", ex);
} catch (InvalidKeyException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1906_INVALID_KEY_ERROR(), ex);
throw new XWSSecurityRuntimeException("Unable to calculate cipher value as invalid key was provided", ex);
} catch(XMLStreamException xse){
logger.log(Level.SEVERE, LogStringsMessages.WSS_1910_ERROR_WRITING_NAMESPACES_CANONICALIZER(xse.getMessage()), xse);
throw new XWSSecurityRuntimeException("Unable to write namespaces to exclusive canonicalizer", xse);
} catch (com.sun.xml.wss.XWSSecurityException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1911_ERROR_WRITING_CIPHERVALUE(ex.getMessage()), ex);
throw new XWSSecurityRuntimeException("Unable to calculate cipher value ", ex);
}
}
public Key decryptKey(byte[] encryptedKey, String encAlgo) throws IOException{
try {
if(mode == Cipher.UNWRAP_MODE){
if (algorithm == null || algorithm.length() == 0) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1912_DECRYPTION_ALGORITHM_NULL());
throw new IOException("Cannot decrypt a key without knowing the algorithm");
}
if(key == null){
logger.log(Level.SEVERE, LogStringsMessages.WSS_1913_DECRYPTION_KEY_NULL());
throw new IOException("Key used to decrypt EncryptedKey cannot be null");
}
if(cipher == null){
initCipher();
}
return cipher.unwrap(encryptedKey,JCEMapper.getJCEKeyAlgorithmFromURI(encAlgo), Cipher.SECRET_KEY);
}
} catch (InvalidKeyException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1906_INVALID_KEY_ERROR(), ex);
throw new XWSSecurityRuntimeException(ex);
} catch (NoSuchAlgorithmException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1904_UNSUPPORTED_KEYENCRYPTION_ALGORITHM(algorithm), ex);
throw new XWSSecurityRuntimeException(ex);
} catch (javax.crypto.NoSuchPaddingException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1905_ERROR_INITIALIZING_CIPHER(), ex);
throw new XWSSecurityRuntimeException(ex);
}
logger.log(Level.SEVERE, LogStringsMessages.WSS_1914_INVALID_CIPHER_MODE(mode));
throw new IOException("Invalid Cipher mode:"+mode);
}
public InputStream decryptData(InputStream is) throws IOException{
try {
if(mode == Cipher.DECRYPT_MODE){
if ( cipher == null ) {
String transformation = convertAlgURIToTransformation(getAlgorithm());
cipher = Cipher.getInstance(transformation);
int len = cipher.getBlockSize();
byte [] iv = new byte[len];
is.read(iv,0,len);
ivSpec = new IvParameterSpec(iv);
cipher.init(mode,key,ivSpec);
}
return new CipherInputStream(is,cipher);
} else {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1914_INVALID_CIPHER_MODE(mode));
throw new IOException("Invalid Cipher mode:"+mode);
}
} catch (InvalidKeyException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1906_INVALID_KEY_ERROR(),ex);
throw new XWSSecurityRuntimeException(ex);
} catch (NoSuchAlgorithmException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1909_UNSUPPORTED_DATAENCRYPTION_ALGORITHM(getAlgorithm()), ex);
throw new XWSSecurityRuntimeException(ex);
} catch (javax.crypto.NoSuchPaddingException ex) {
logger.log(Level.SEVERE, LogStringsMessages.WSS_1905_ERROR_INITIALIZING_CIPHER(), ex);
throw new XWSSecurityRuntimeException(ex);
}catch (InvalidAlgorithmParameterException invalidAPE){
logger.log(Level.SEVERE, LogStringsMessages.WSS_1915_INVALID_ALGORITHM_PARAMETERS(getAlgorithm()), invalidAPE);
throw new XWSSecurityRuntimeException(invalidAPE);
}
}
}
|