/* | |
* Copyright 2003-2004 The Apache Software Foundation. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
* | |
*/ | |
package org.apache.ws.security.message; | |
import org.apache.ws.security.SOAPConstants; | |
import org.apache.ws.security.WSConstants; | |
import org.apache.ws.security.WSEncryptionPart; | |
import org.apache.ws.security.WSSecurityException; | |
import org.apache.ws.security.conversation.ConversationException; | |
import org.apache.ws.security.message.token.Reference; | |
import org.apache.ws.security.message.token.SecurityTokenReference; | |
import org.apache.ws.security.util.WSSecurityUtil; | |
import org.apache.xml.security.encryption.EncryptedData; | |
import org.apache.xml.security.encryption.XMLCipher; | |
import org.apache.xml.security.encryption.XMLEncryptionException; | |
import org.apache.xml.security.keys.KeyInfo; | |
import org.w3c.dom.Document; | |
import org.w3c.dom.Element; | |
import org.w3c.dom.Node; | |
import javax.crypto.SecretKey; | |
import java.util.Vector; | |
/** | |
* Encrypts and signs parts of a message with derived keys derived from a | |
* symmetric key. This symmetric key will be included as an EncryptedKey | |
* | |
* @author Ruchith Fernando (ruchith.fernando@gmail.com) | |
*/ | |
public class WSSecDKEncrypt extends WSSecDerivedKeyBase { | |
protected String symEncAlgo = WSConstants.AES_128; | |
public Document build(Document doc, WSSecHeader secHeader) | |
throws WSSecurityException, ConversationException { | |
/* | |
* Setup the encrypted key | |
*/ | |
prepare(doc); | |
this.envelope = doc.getDocumentElement(); | |
/* | |
* prepend elements in the right order to the security header | |
*/ | |
prependDKElementToHeader(secHeader); | |
SOAPConstants soapConstants = WSSecurityUtil.getSOAPConstants(envelope); | |
if (parts == null) { | |
parts = new Vector(); | |
WSEncryptionPart encP = new WSEncryptionPart(soapConstants | |
.getBodyQName().getLocalPart(), soapConstants | |
.getEnvelopeURI(), "Content"); | |
parts.add(encP); | |
} | |
Element externRefList = encryptForExternalRef(null, parts); | |
addExternalRefElement(externRefList, secHeader); | |
return doc; | |
} | |
private Vector doEncryption(Document doc, byte[] secretKey, Vector references) throws WSSecurityException { | |
SecretKey key = WSSecurityUtil.prepareSecretKey(this.symEncAlgo, secretKey); | |
XMLCipher xmlCipher = null; | |
try { | |
xmlCipher = XMLCipher.getInstance(symEncAlgo); | |
} catch (XMLEncryptionException e3) { | |
throw new WSSecurityException( | |
WSSecurityException.UNSUPPORTED_ALGORITHM, null, null, e3); | |
} | |
Vector encDataRefs = new Vector(); | |
if(envelope == null) { | |
envelope = doc.getDocumentElement(); | |
} | |
for (int part = 0; part < references.size(); part++) { | |
WSEncryptionPart encPart = (WSEncryptionPart) references.get(part); | |
String idToEnc = encPart.getId(); | |
String elemName = encPart.getName(); | |
String nmSpace = encPart.getNamespace(); | |
String modifier = encPart.getEncModifier(); | |
/* | |
* Third step: get the data to encrypt. | |
*/ | |
Element body = null; | |
if (idToEnc != null) { | |
body = WSSecurityUtil.findElementById(document | |
.getDocumentElement(), idToEnc, WSConstants.WSU_NS); | |
if (body == null) { | |
body = WSSecurityUtil.findElementById(document | |
.getDocumentElement(), idToEnc, null); | |
} | |
} else { | |
body = (Element) WSSecurityUtil.findElement(envelope, elemName, | |
nmSpace); | |
} | |
if (body == null) { | |
throw new WSSecurityException(WSSecurityException.FAILURE, | |
"noEncElement", new Object[] { "{" + nmSpace + "}" | |
+ elemName }); | |
} | |
boolean content = modifier.equals("Content") ? true : false; | |
String xencEncryptedDataId = "EncDataId-" + body.hashCode(); | |
/* | |
* Forth step: encrypt data, and set necessary attributes in | |
* xenc:EncryptedData | |
*/ | |
try { | |
//Create the SecurityTokenRef to the DKT | |
KeyInfo keyInfo = new KeyInfo(document); | |
SecurityTokenReference secToken = new SecurityTokenReference(document); | |
Reference ref = new Reference(document); | |
ref.setURI("#" + dktId); | |
secToken.setReference(ref); | |
keyInfo.addUnknownElement(secToken.getElement()); | |
xmlCipher.init(XMLCipher.ENCRYPT_MODE, key); | |
EncryptedData encData = xmlCipher.getEncryptedData(); | |
encData.setId(xencEncryptedDataId); | |
encData.setKeyInfo(keyInfo); | |
xmlCipher.doFinal(doc, body, content); | |
} catch (Exception e2) { | |
throw new WSSecurityException( | |
WSSecurityException.FAILED_ENC_DEC, null, null, e2); | |
} | |
encDataRefs.add(new String("#" + xencEncryptedDataId)); | |
} | |
return encDataRefs; | |
} | |
/** | |
* Encrypt one or more parts or elements of the message (external). | |
* | |
* This method takes a vector of <code>WSEncryptionPart</code> object that | |
* contain information about the elements to encrypt. The method call the | |
* encryption method, takes the reference information generated during | |
* encryption and add this to the <code>xenc:Reference</code> element. | |
* This method can be called after <code>prepare()</code> and can be | |
* called multiple times to encrypt a number of parts or elements. | |
* | |
* </p> | |
* | |
* The method generates a <code>xenc:Reference</code> element that <i>must</i> | |
* be added to the SecurityHeader. See <code>addExternalRefElement()</code>. | |
* | |
* </p> | |
* | |
* If the <code>dataRef</code> parameter is <code>null</code> the method | |
* creates and initializes a new Reference element. | |
* | |
* @param dataRef | |
* A <code>xenc:Reference</code> element or <code>null</code> | |
* @param references | |
* A vector containing WSEncryptionPart objects | |
* @return Returns the updated <code>xenc:Reference</code> element | |
* @throws WSSecurityException | |
*/ | |
public Element encryptForExternalRef(Element dataRef, Vector references) | |
throws WSSecurityException { | |
Vector encDataRefs = doEncryption(document, derivedKeyBytes, | |
references); | |
Element referenceList = dataRef; | |
if (referenceList == null) { | |
referenceList = document.createElementNS(WSConstants.ENC_NS, | |
WSConstants.ENC_PREFIX + ":ReferenceList"); | |
} | |
createDataRefList(document, referenceList, encDataRefs); | |
return referenceList; | |
} | |
/** | |
* Adds (prepends) the external Reference element to the Security header. | |
* | |
* The reference element <i>must</i> be created by the | |
* <code>encryptForExternalRef() </code> method. The method adds the | |
* reference element in the SecurityHeader. | |
* | |
* @param dataRef | |
* The external <code>enc:Reference</code> element | |
* @param secHeader | |
* The security header. | |
*/ | |
public void addExternalRefElement(Element referenceList, WSSecHeader secHeader) { | |
Node node = dkt.getElement().getNextSibling(); | |
if(node == null || (node != null && !(node instanceof Element))) { | |
//If (at this moment) DerivedKeyToken is the LAST element of | |
//the security header | |
secHeader.getSecurityHeader().appendChild(referenceList); | |
} else { | |
secHeader.getSecurityHeader().insertBefore(referenceList, node); | |
} | |
} | |
public static Element createDataRefList(Document doc, | |
Element referenceList, Vector encDataRefs) { | |
for (int i = 0; i < encDataRefs.size(); i++) { | |
String dataReferenceUri = (String) encDataRefs.get(i); | |
Element dataReference = doc.createElementNS(WSConstants.ENC_NS, | |
WSConstants.ENC_PREFIX + ":DataReference"); | |
dataReference.setAttributeNS(null, "URI", dataReferenceUri); | |
referenceList.appendChild(dataReference); | |
} | |
return referenceList; | |
} | |
public void setSymmetricEncAlgorithm(String algo) { | |
symEncAlgo = algo; | |
} | |
/** | |
* @see org.apache.ws.security.message.WSSecDerivedKeyBase#getDerivedKeyLength() | |
*/ | |
protected int getDerivedKeyLength() throws WSSecurityException{ | |
return (this.derivedKeyLength > 0) ? this.derivedKeyLength : | |
WSSecurityUtil.getKeyLength(this.symEncAlgo); | |
} | |
} |