EncryptPartialMessageProcessor.java

  1. /*
  2.  * AdroitLogic UltraESB Enterprise Service Bus
  3.  *
  4.  * Copyright (c) 2010-2012 AdroitLogic Private Ltd. (http://adroitlogic.org). All Rights Reserved.
  5.  *
  6.  * GNU Affero General Public License Usage
  7.  *
  8.  * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
  9.  * Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option)
  10.  * any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  13.  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
  14.  * more details.
  15.  *
  16.  * You should have received a copy of the GNU Affero General Public License along with this program (See LICENSE-AGPL.TXT).
  17.  * If not, see http://www.gnu.org/licenses/agpl-3.0.html
  18.  *
  19.  * Commercial Usage
  20.  *
  21.  * Licensees holding valid UltraESB Commercial licenses may use this file in accordance with the UltraESB Commercial
  22.  * License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written
  23.  * agreement between you and AdroitLogic.
  24.  *
  25.  * If you are unsure which license is appropriate for your use, or have questions regarding the use of this file,
  26.  * please contact AdroitLogic at info@adroitlogic.com
  27.  */
  28. /*
  29.  * Modificato da Link.it (https://link.it) per supportare le seguenti funzionalità:
  30.  * - firma e cifratura degli attachments
  31.  * - cifratura con chiave simmetrica
  32.  * - supporto CRL
  33.  *
  34.  * Copyright (c) 2011-2025 Link.it srl (https://link.it).
  35.  *
  36.  */

  37. package org.openspcoop2.security.message.soapbox;

  38. import java.io.ByteArrayInputStream;
  39. import java.io.ByteArrayOutputStream;
  40. import java.io.IOException;
  41. import java.io.InputStream;
  42. import java.io.OutputStream;
  43. import java.security.InvalidKeyException;
  44. import java.security.NoSuchAlgorithmException;
  45. import java.security.SecureRandom;
  46. import java.security.Security;
  47. import java.util.ArrayList;
  48. import java.util.HashMap;
  49. import java.util.Iterator;
  50. import java.util.List;
  51. import java.util.Map;

  52. import javax.activation.DataHandler;
  53. import javax.crypto.Cipher;
  54. import javax.crypto.SecretKey;
  55. import javax.crypto.spec.IvParameterSpec;
  56. import javax.xml.namespace.QName;
  57. import javax.xml.soap.AttachmentPart;
  58. import javax.xml.soap.MimeHeader;
  59. import javax.xml.soap.MimeHeaders;
  60. import javax.xml.soap.SOAPElement;
  61. import javax.xml.soap.SOAPException;
  62. import javax.xml.soap.SOAPHeaderElement;

  63. import org.adroitlogic.soapbox.CryptoSupport;
  64. import org.adroitlogic.soapbox.CryptoUtil;
  65. import org.adroitlogic.soapbox.EncryptionRequest;
  66. import org.adroitlogic.soapbox.InvalidMessageDataException;
  67. import org.adroitlogic.soapbox.InvalidOptionException;
  68. import org.adroitlogic.soapbox.MessageSecurityContext;
  69. import org.adroitlogic.soapbox.Processor;
  70. import org.adroitlogic.soapbox.SBConstants;
  71. import org.adroitlogic.soapbox.SecurityFailureException;
  72. import org.apache.xml.security.encryption.EncryptedData;
  73. import org.apache.xml.security.encryption.XMLCipher;
  74. import org.apache.xml.security.encryption.XMLEncryptionException;
  75. import org.apache.xml.security.keys.KeyInfo;
  76. import org.openspcoop2.message.OpenSPCoop2SoapMessage;
  77. import org.openspcoop2.security.message.constants.WSSAttachmentsConstants;
  78. import org.openspcoop2.utils.LoggerWrapperFactory;
  79. import org.openspcoop2.utils.io.Base64Utilities;
  80. import org.slf4j.Logger;
  81. import org.w3c.dom.Document;
  82. import org.w3c.dom.Element;

  83. import com.sun.xml.wss.core.EncryptedDataHeaderBlock;
  84. import com.sun.xml.wss.swa.MimeConstants;

  85. /**
  86.  * EncryptPartialMessageProcessor
  87.  *
  88.  * Author of the original AdroitLogic code:
  89.  * @author asankha
  90.  *
  91.  * Authors of the Link.it modification to the code:
  92.  * @author Andrea Poli (apoli@link.it)
  93.  * @author $Author$
  94.  * @version $Rev$, $Date$
  95.  */
  96. public class EncryptPartialMessageProcessor implements Processor {

  97.     private static final Logger logger = LoggerWrapperFactory.getLogger(EncryptPartialMessageProcessor.class);


  98.     private List<QName> elements;
  99.     private List<Boolean> elementsEncryptContent;
  100.     private Map<AttachmentPart, Boolean> attachments;
  101.     private OpenSPCoop2SoapMessage message;
  102.     public void setMessage(OpenSPCoop2SoapMessage message) {
  103.         this.message = message;
  104.     }
  105.     private String actor;
  106.     private boolean mustUnderstand;
  107.     public void setActor(String actor) {
  108.         this.actor = actor;
  109.     }
  110.     public void setMustUnderstand(boolean mustUnderstand) {
  111.         this.mustUnderstand = mustUnderstand;
  112.     }

  113.     public EncryptPartialMessageProcessor() {
  114.         this.elements = new ArrayList<QName>();
  115.         this.elementsEncryptContent = new ArrayList<Boolean>();
  116.         this.attachments = new HashMap<AttachmentPart, Boolean>();
  117.     }

  118.     public void addElementToEncrypt(QName element , boolean content) {
  119.         this.elements.add(element);
  120.         this.elementsEncryptContent.add(content);
  121.     }

  122.     public void addAttachmentToEncrypt(AttachmentPart part, boolean contentOnly) {
  123.         this.attachments.put(part, contentOnly);
  124.     }


  125.     @Override
  126.     public void process(org.adroitlogic.soapbox.SecurityConfig secConfig, MessageSecurityContext msgSecCtx) {

  127.         Document doc = msgSecCtx.getDocument();

  128.         // ensure existence of the wsse:Security header, and create one if none exists
  129.         Element wsseSecurityElem = null;
  130.         try{
  131.             wsseSecurityElem = WSSUtils.getWSSecurityHeader(msgSecCtx.getDocument(), this.actor, this.mustUnderstand);
  132.         }catch(Exception e){
  133.             throw new SecurityFailureException(e.getMessage(), e);
  134.         }
  135.         //Element wsseSecurityElem = CryptoUtil.getWSSecurityHeader(doc);
  136.        
  137.         // we will not encrypt an already encrypted document
  138.         if (CryptoUtil.getFirstChildOrNull(wsseSecurityElem, SBConstants.XENC, "EncryptedKey") != null) {
  139.             throw new InvalidMessageDataException("Message is already encrypted");
  140.         }

  141.         Element env = doc.getDocumentElement();

  142.         String secTokenRef = CryptoUtil.getRandomId();

  143.         // by default Body is encrypted
  144.         if(this.elements.isEmpty() && this.attachments.isEmpty()){
  145.             this.elements.add(new QName(env.getNamespaceURI(), "Body"));
  146.             this.elementsEncryptContent.add(true);
  147.         }


  148.         // Process element e attachments
  149.         try {

  150.             processElements(msgSecCtx, secTokenRef);
  151.             processAttachments(msgSecCtx);

  152.         } catch (Exception e) {
  153.             throw new SecurityFailureException("Error encrypting an element or an attachment", e);
  154.         }
  155.        
  156.        
  157.        
  158.         // Process KeyInstance
  159.        
  160.         Cipher cipher = null;
  161.         String cipherValue = null;

  162.         EncryptionRequest encReq = msgSecCtx.getEncryptionRequest();

  163.         try {
  164.             SoapBoxSecurityConfig secConfigOpenSPCoop = (SoapBoxSecurityConfig)secConfig;

  165.             Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
  166.             cipher = CryptoSupport.getInstance().getCipherInstance(encReq.getEncryptionAlgoURI());

  167.             byte[] encKey = null;
  168.             SecretKey encKeyObject = null;
  169.             try {
  170.                 encKeyObject = encReq.getEphemeralKey();
  171.                 encKey = encReq.getEphemeralKey().getEncoded();
  172.             } catch (NoSuchAlgorithmException ignore) { /*will/should not happen*/ }

  173.             if( secConfigOpenSPCoop.isSymmetricSharedKey() ){
  174.                
  175.                 int blockSize = cipher.getBlockSize();
  176.                 if(blockSize==0){
  177.                     blockSize = 8;
  178.                 }
  179.                 //System.out.println("cipher (Algoritmo["+cipher.getAlgorithm()+"]) blksize: " + blockSize);
  180.                                
  181.                 SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
  182.                 byte[] iv = new byte[blockSize];
  183.                 randomSecureRandom.nextBytes(iv);
  184.                 IvParameterSpec ivParams = new IvParameterSpec(iv);
  185.                
  186.                 //cipher.init(Cipher.WRAP_MODE, secConfigOpenSPCoop.getSymmetricKey(encReq.getCertAlias()), new IvParameterSpec(new byte[blockSize]));
  187.                 cipher.init(Cipher.WRAP_MODE, secConfigOpenSPCoop.getSymmetricKey(encReq.getCertAlias()), ivParams);
  188.                
  189.                 cipherValue = Base64Utilities.encodeAsString(cipher.wrap(encKeyObject));
  190.             }
  191.             else{

  192.                 cipher.init(Cipher.ENCRYPT_MODE, secConfig.getTrustedCertificatesByAlias(encReq.getCertAlias())[0]);
  193.                
  194.                 if(encKey==null) {
  195.                     throw new SecurityFailureException("EncKey is null");
  196.                 }
  197.                
  198.                 if (cipher.getBlockSize() > 0 && cipher.getBlockSize() < encKey.length) {
  199.                     throw new SecurityFailureException("Public key algorithm too weak to encrypt symmetric key " +
  200.                             " - cipher block size : " + cipher.getBlockSize() + " encrypted bytes length : " + encKey.length);
  201.                 }

  202.                 cipherValue = Base64Utilities.encodeAsString(cipher.doFinal(encKey));
  203.             }

  204.         } catch (InvalidKeyException e) {
  205.             e.printStackTrace(System.err);
  206.             throw new SecurityFailureException("Error preparing cipher for encryption : " + encReq.getEncryptionAlgoURI());
  207.         } catch (Exception e) {
  208.             throw new SecurityFailureException("Failed to encrypt session key", e);
  209.         } finally {
  210.             CryptoSupport.getInstance().returnCipherInstance(cipher);
  211.         }

  212.         Element encryptedKeyElem = createEncryptedKey(doc, encReq, cipherValue, secConfig, msgSecCtx, secTokenRef);
  213.         Element firstChild = CryptoUtil.getFirstElementChild(wsseSecurityElem);
  214.         if (firstChild != null) {
  215.             wsseSecurityElem.insertBefore(encryptedKeyElem, firstChild);
  216.         } else {
  217.             wsseSecurityElem.appendChild(encryptedKeyElem);
  218.         }
  219.        
  220.     }

  221.     private Element createEncryptedKey(Document doc, EncryptionRequest encReq,
  222.             String cipherValue, org.adroitlogic.soapbox.SecurityConfig secConfig, MessageSecurityContext msgSecCtx, String referenceId) {

  223.         // create EncryptedKey element, and append EncryptionMethod with algorithm used
  224.         Element encryptedKeyElem = doc.createElementNS(SBConstants.XENC, "xenc:EncryptedKey");
  225.         encryptedKeyElem.setAttribute("Id", referenceId);
  226.         Element encryptionMethodElem = doc.createElementNS(SBConstants.XENC, "xenc:EncryptionMethod");
  227.         encryptionMethodElem.setAttribute("Algorithm", encReq.getEncryptionAlgoURI());
  228.         encryptedKeyElem.appendChild(encryptionMethodElem);

  229.         // create and attach the keyinfo element
  230.         SoapBoxSecurityConfig securityConfigOpenSPCoop = (SoapBoxSecurityConfig) secConfig;
  231.         if(securityConfigOpenSPCoop.isSymmetricSharedKey()){
  232.             encryptedKeyElem.appendChild(SymmetricCryptoUtils.createKeyInfoElement(doc, encReq, msgSecCtx, secConfig));
  233.         }else{
  234.             //encryptedKeyElem.appendChild(CryptoUtil.createKeyInfoElement(doc, encReq, msgSecCtx, secConfig));
  235.             encryptedKeyElem.appendChild(WSSUtils.createKeyInfoElement(doc, encReq, msgSecCtx, secConfig));
  236.         }

  237.         // create CipherData element and store the encrypted cipher value
  238.         Element cipherDataElem = doc.createElementNS(SBConstants.XENC, "xenc:CipherData");
  239.         Element cipherValueElem = doc.createElementNS(SBConstants.XENC, "xenc:CipherValue");
  240.         cipherValueElem.setTextContent(cipherValue);
  241.         cipherDataElem.appendChild(cipherValueElem);
  242.         encryptedKeyElem.appendChild(cipherDataElem);

  243.         // crate ReferenceList element and store encrypted element IDs
  244.         Element referenceListElem = doc.createElementNS(SBConstants.XENC, "xenc:ReferenceList");
  245.         for (String id : msgSecCtx.getEncryptedReferenceList()) {
  246.             Element dataReferenceElem = doc.createElementNS(SBConstants.XENC, "xenc:DataReference");
  247.             dataReferenceElem.setAttribute("URI", "#" + id);
  248.             referenceListElem.appendChild(dataReferenceElem);
  249.         }
  250.         encryptedKeyElem.appendChild(referenceListElem);

  251.         return encryptedKeyElem;
  252.     }

  253.     private void processElements(MessageSecurityContext msgSecCtx,
  254.             String referenceId) throws Exception {

  255.         Document doc = msgSecCtx.getDocument();
  256.         Element env = doc.getDocumentElement();
  257.         // TODO
  258.         int index = 0;
  259.         for(QName name : this.elements) {
  260.             Element encElement = CryptoUtil.getFirstChild(env, name.getNamespaceURI(), name.getLocalPart());
  261.            
  262.             // L'attributo wsu:Id non serve nella encryption
  263. //          String encId = encElement.getAttributeNS(SBConstants.WSU, "Id");
  264. //          if (encId == null || encId.length() == 0) {
  265. //              encId = encElement.getAttribute("Id");
  266. //          }
  267. //          if (encId == null || encId.length() == 0) {
  268. //              encId = CryptoUtil.getRandomId();
  269. //              encElement.setAttributeNS(SBConstants.WSU, "wsu:Id", encId);
  270. //              CryptoUtil.setWsuId(encElement, encId);
  271. //          }

  272.             EncryptionRequest encReq = msgSecCtx.getEncryptionRequest();
  273.             String symEncAlgo = encReq.getSymmetricKeyAlgoURI();
  274.             XMLCipher xmlCipher = null;
  275.             try {
  276.                 //xmlCipher = XMLCipher.getInstance(symEncAlgo);        
  277.                 xmlCipher = CryptoSupport.getInstance().getXMLCipher(symEncAlgo);

  278.                 xmlCipher.init(XMLCipher.ENCRYPT_MODE, msgSecCtx.getEncryptionRequest().getEphemeralKey());
  279.                 EncryptedData encData = xmlCipher.getEncryptedData();
  280.                 String encEltId = CryptoUtil.getRandomId();
  281.                 encData.setId(encEltId);

  282.                 KeyInfo keyInfo = new KeyInfo(doc);
  283.                 Element securityTokenReferenceElem = doc.createElementNS(SBConstants.WSSE, "wsse:SecurityTokenReference");
  284.                 securityTokenReferenceElem.setAttributeNS(SBConstants.XMLNS, "xmlns:wsse", SBConstants.WSSE);
  285.                 Element referenceElem = doc.createElementNS(SBConstants.WSSE, "wsse:Reference");
  286.                 referenceElem.setAttribute("URI", "#" + referenceId);
  287.                 securityTokenReferenceElem.appendChild(referenceElem);

  288.                 keyInfo.addUnknownElement(securityTokenReferenceElem);
  289.                 encData.setKeyInfo(keyInfo);

  290.                 xmlCipher.doFinal(encElement.getOwnerDocument(), encElement, this.elementsEncryptContent.get(index++));
  291.                 msgSecCtx.addEncryptedReference(encEltId);

  292.             } catch (XMLEncryptionException e) {
  293.                 throw new InvalidOptionException("Unsupported algorithm : " + symEncAlgo, e);
  294.             } finally {
  295.                 try{
  296.                     CryptoSupport.getInstance().returnXMLCipherInstance(symEncAlgo, xmlCipher);
  297.                 }catch(Exception e){
  298.                     EncryptPartialMessageProcessor.logger.error(e.getMessage(),e);
  299.                 }
  300.             }
  301.         }
  302.     }

  303.     private static byte[] serializeHeaders(List<MimeHeader> mhs) throws Exception {
  304.         ByteArrayOutputStream baos = new ByteArrayOutputStream();

  305.         try {

  306.             StringBuilder line = new StringBuilder();

  307.             for (MimeHeader mh : mhs) {

  308.                 String name = mh.getName();
  309.                 String vlue = mh.getValue();

  310.                 line.append(name);
  311.                 line.append(":");
  312.                 line.append(vlue);
  313.                 line.append("\r\n");

  314.             }

  315.             line.append("\r\n");
  316.             byte[] b = line.toString().getBytes("US-ASCII");
  317.             baos.write(b, 0, b.length);

  318.         } catch (Exception e) {
  319.             throw new Exception(e);
  320.         }

  321.         return baos.toByteArray();
  322.     }

  323.     private void processAttachments(MessageSecurityContext msgSecCtx) throws Exception {

  324.         if(this.attachments.size()<=0){
  325.             return;
  326.         }

  327.         Cipher _attachmentEncryptor = null;
  328.         try {
  329.             EncryptionRequest encReq = msgSecCtx.getEncryptionRequest();

  330.             String encAlgo = encReq.getSymmetricKeyAlgoURI();

  331.             _attachmentEncryptor = CryptoSupport.getInstance().getCipherInstance(encAlgo);
  332.             _attachmentEncryptor.init(Cipher.ENCRYPT_MODE, encReq.getEphemeralKey());

  333.             for(AttachmentPart p : this.attachments.keySet()) {

  334.                 boolean contentOnly = this.attachments.get(p);

  335.                 // create n push an ED

  336.                 EncryptedDataHeaderBlock edhb = new EncryptedDataHeaderBlock();

  337.                 String id = CryptoUtil.getRandomId();

  338.                 edhb.setId(id);
  339.                 edhb.setType( (contentOnly ?  WSSAttachmentsConstants.ATTACHMENT_CONTENT_ONLY_URI : WSSAttachmentsConstants.ATTACHMENT_COMPLETE_URI));
  340.                 edhb.setMimeType(p.getContentType());
  341.                 String uri = p.getContentId();
  342.                 if (uri != null) {          
  343.                     if(uri.startsWith("<")){
  344.                         uri = "cid:" + uri.substring(1, uri.length()-1);
  345.                     }else{
  346.                         uri = "cid:" + uri;
  347.                     }
  348.                 } else {
  349.                     uri = p.getContentLocation();
  350.                 }

  351.                 edhb.getCipherReference(true, uri);
  352.                 edhb.setEncryptionMethod(encAlgo);
  353.                 edhb.addTransform((contentOnly ?  WSSAttachmentsConstants.ATTACHMENT_CIPHERTEXT_TRANSFORM_URI : WSSAttachmentsConstants.ATTACHMENT_COMPLETE_TRANSFORM_URI));

  354.                 //System.out.println(" --PRIMA ENCRYPT --");
  355.                 //System.out.println(org.openspcoop2.pdd.logger.Dump.dumpMessage(this.message, true));
  356.                                
  357.                 AttachmentPart encPart = EncryptPartialMessageProcessor.encryptAttachment(p, contentOnly, _attachmentEncryptor, this.message.createAttachmentPart());

  358.                 //System.out.println(" --DOPO ENCRYPT --");
  359.                 //System.out.println(org.openspcoop2.pdd.logger.Dump.dumpMessage(this.message, true));
  360.                
  361. //              this.attachments.remove(p); // Concurrent Modification
  362.                 MimeHeaders mhs = new MimeHeaders();
  363.                 mhs.addHeader(MimeConstants.CONTENT_ID, p.getContentId());
  364.                 this.message.removeAttachments(mhs);
  365.                 this.message.addAttachmentPart(encPart);
  366.                
  367.                 msgSecCtx.addEncryptedReference(edhb.getId());
  368.                 //Element wssHeader = CryptoUtil.getWSSecurityHeader(msgSecCtx.getDocument());
  369.                 SOAPHeaderElement wssHeader = WSSUtils.getWSSecurityHeader(this.message, this.actor, this.mustUnderstand);
  370.                
  371.                 SOAPElement elementToInsert = edhb.getAsSoapElement();
  372.                 wssHeader.addChildElement(elementToInsert);
  373.                
  374.                 /*
  375.                 SOAPElement soapWssHeader = (SOAPElement) wssHeader;
  376.                 SecurityHeader _secHeader = new SecurityHeader(soapWssHeader) ;
  377.                 _secHeader.appendChild(edhb);*/            
  378.             }
  379.             this.attachments.clear();
  380.         }
  381.         finally {
  382.             CryptoSupport.getInstance().returnCipherInstance(_attachmentEncryptor);
  383.         }
  384.     }

  385.     private static AttachmentPart encryptAttachment(AttachmentPart part, boolean contentOnly, Cipher cipher, AttachmentPart encPart) throws Exception {

  386.         byte[] cipherInput = (contentOnly) ? EncryptPartialMessageProcessor.getBytesFromAttachments(part.getDataHandler()) : EncryptPartialMessageProcessor.getCipherInput(part);
  387.         byte[] cipherOutput = cipher.doFinal(cipherInput);
  388.        
  389.         byte[] iv = cipher.getIV();
  390.         byte[] encryptedBytes = new byte[iv.length + cipherOutput.length];

  391.         System.arraycopy(iv, 0, encryptedBytes, 0, iv.length);
  392.         System.arraycopy(cipherOutput, 0, encryptedBytes, iv.length, cipherOutput.length);

  393.         int cLength  = encryptedBytes.length;
  394.         String cType = MimeConstants.APPLICATION_OCTET_STREAM_TYPE;
  395.         String uri   = part.getContentId();
  396.         //Step 9 and 10.SWA spec.

  397.         if (uri != null){
  398.             encPart.setMimeHeader(MimeConstants.CONTENT_ID, uri);
  399.         }else {
  400.             uri = part.getContentLocation();
  401.             if (uri != null){
  402.                 encPart.setMimeHeader(MimeConstants.CONTENT_LOCATION, uri);
  403.             }
  404.         }
  405.         encPart.setContentType(cType);
  406.         encPart.setMimeHeader(MimeConstants.CONTENT_LENGTH, Integer.toString(cLength));
  407.         encPart.setMimeHeader(MimeConstants.CONTENT_TRANSFER_ENCODING, "base64");

  408.         EncryptedAttachmentDataHandler dh = new EncryptedAttachmentDataHandler(new EncryptedAttachmentDataSource(encryptedBytes));
  409.         encPart.setDataHandler(dh);

  410.         cipherInput = (contentOnly) ? EncryptPartialMessageProcessor.getBytesFromAttachments(encPart.getDataHandler()) : EncryptPartialMessageProcessor.getCipherInput(encPart);

  411.         return encPart;
  412.     }

  413.     private static byte[] getCipherInput(AttachmentPart part) throws Exception,
  414.     SOAPException, IOException {
  415.         byte[] cipherInput;
  416.         byte[] headers = EncryptPartialMessageProcessor.getAttachmentHeaders(part.getAllMimeHeaders());
  417.         byte[] content = EncryptPartialMessageProcessor.getBytesFromAttachments(part.getDataHandler());

  418.         cipherInput = new byte[headers.length+content.length];

  419.         System.arraycopy(headers, 0, cipherInput, 0, headers.length);
  420.         System.arraycopy(content, 0, cipherInput, headers.length, content.length);
  421.         return cipherInput;
  422.     }

  423.     private static byte[] getAttachmentHeaders(Iterator<MimeHeader> mhItr) throws Exception {

  424.         List<MimeHeader> mhs = new ArrayList<MimeHeader>();
  425.         while (mhItr.hasNext()) mhs.add(mhItr.next());
  426.         return EncryptPartialMessageProcessor.serializeHeaders(mhs);

  427.     }

  428.     private static byte[] getBytesFromAttachments(DataHandler dh) throws SOAPException, IOException {

  429.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  430.         dh.writeTo(baos);
  431.         return Base64Utilities.encodeAsString(baos.toByteArray()).getBytes("US-ASCII");

  432.     }

  433.     private static class EncryptedAttachmentDataHandler extends javax.activation.DataHandler {

  434.         EncryptedAttachmentDataHandler(javax.activation.DataSource ds) {
  435.             super(ds);
  436.         }

  437.         @Override
  438.         public void writeTo(OutputStream os) throws java.io.IOException {
  439.             ((ByteArrayOutputStream) getDataSource().getOutputStream()).writeTo(os);
  440.         }
  441.     }

  442.     private static class EncryptedAttachmentDataSource implements javax.activation.DataSource {
  443.         byte[] datasource;

  444.         EncryptedAttachmentDataSource(byte[] ds) {
  445.             this.datasource = ds;
  446.         }

  447.         @Override
  448.         public String getContentType() {
  449.             return MimeConstants.APPLICATION_OCTET_STREAM_TYPE;
  450.         }

  451.         @Override
  452.         public InputStream getInputStream() throws java.io.IOException {
  453.             return new ByteArrayInputStream(this.datasource);
  454.         }

  455.         @Override
  456.         public String getName() {
  457.             return "Encrypted Attachment DataSource";
  458.         }

  459.         @Override
  460.         public OutputStream getOutputStream() throws java.io.IOException {
  461.             ByteArrayOutputStream baos = new ByteArrayOutputStream();
  462.             baos.write(this.datasource, 0, this.datasource.length);
  463.             return baos;
  464.         }
  465.     }

  466. }