You can use the one argument version of the decryptKey method. There you don't need to specify the algorithm, it's determined automatically from the EncryptedData element.

Vishal

Peter Hendry wrote:
Thanks for the response. Changing to

final SecretKey unwrappedKey = (SecretKey)cipher.decryptKey(encryptedKey, XMLCipher.TRIPLEDES);
does make it work! This leads onto the issue of how the receiver knows the 
symmetric key algorithm? This information is not transmitted in the 
EncryptedKey. The code I am seeing this problem in is for WS-Security and there 
is no indication in the EncryptedKey sent (example below) of this algorithm. 
Does it have to be supplied out of band?

  <xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#";>
    <xenc:EncryptionMethod
        xmlns:xenc="http://www.w3.org/2001/04/xmlenc#";
        Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
    <xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#";>
      <xenc:CipherValue 
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#";>op+6IqOzXDvnnRJnibidFEre1nC5km6+1vkzM7mD4yR9r
nVYFo3SWq6t8r3s0jJj9HR6J4y4EQHW
ay7Qhat8gMd8q9L9YStf5lNroSC3Co1HNOWokJ7aL759a0ifN3fT5djYIEVwzwwgpZHtsJjz+j99
Ot+s+Tk6Kfhd5oe+I9Q=</xenc:CipherValue>
    </xenc:CipherData>
    <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#";>
      <wsse:SecurityTokenReference
          
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
          wsu:Id="id19351067"
          
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";>
        <wsse:KeyIdentifier
            
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary";
            
ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier";>
Xeg55vRyK3ZhAEhEf+YT0z986L0=</wsse:KeyIdentifier>
      </wsse:SecurityTokenReference>
    </ds:KeyInfo>
    <xenc:ReferenceList>
      <xenc:DataReference URI="#id16134229"/>
    </xenc:ReferenceList>
</xenc:EncryptedKey>
Pete
Vishal Mahajan wrote:
Problem seems to be in this line:

final SecretKey unwrappedKey = (SecretKey)cipher.decryptKey(encryptedKey, 
XMLCipher.RSA_v1dot5);

The second parameter to decryptKey method needs to be the symmetric key algorithm.

Vishal

Peter Hendry wrote:
Sorry, I forgot the error produced in JDK 1.5

Original Exception was java.security.InvalidKeyException: Wrong algorithm: DESede or TripleDES required at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(Unknown Source) at org.apache.xml.security.encryption.XMLCipher.decryptElement(Unknown Source) at org.apache.xml.security.encryption.XMLCipher.doFinal(Unknown Source) at com.capeclear.pgh.stuff.SecurityKeyTests.main(SecurityKeyTests.java:98)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90) java.security.InvalidKeyException: Wrong algorithm: DESede or TripleDES required
    at com.sun.crypto.provider.SunJCE_aa.a(DashoA12275)
    at com.sun.crypto.provider.SunJCE_m.a(DashoA12275)
    at com.sun.crypto.provider.SunJCE_h.a(DashoA12275)
    at com.sun.crypto.provider.DESedeCipher.engineInit(DashoA12275)
    at javax.crypto.Cipher.init(DashoA12275)
    at javax.crypto.Cipher.init(DashoA12275)
at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(Unknown Source) at org.apache.xml.security.encryption.XMLCipher.decryptElement(Unknown Source) at org.apache.xml.security.encryption.XMLCipher.doFinal(Unknown Source) at com.capeclear.pgh.stuff.SecurityKeyTests.main(SecurityKeyTests.java:98)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)

Pete

Peter Hendry wrote:
The class attached contains test code that works Ok under JDK 1.4 but has never worked under 1.5. The scenario is where the secret key is to be included with the message and encrypted using a public key then decrypted by the recipient using their private key. When the key is decrypted an instance of SecretKeySpec is returned with its algorithm set to RSA (the original key is DESEde). This happens on both 1.4 and 1.5 but it only fails to decrypt the data in 1.5.

Any help/pointers appreciated.

Pete



------------------------------------------------------------------------

package pgh;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Security;
import java.security.spec.KeySpec;

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.xml.security.encryption.EncryptedKey;
import org.apache.xml.security.encryption.XMLCipher;
import org.apache.xml.security.transforms.Transforms;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;


public class SecurityKeyTests {

    static {
        Security.addProvider(new BouncyCastleProvider());
        org.apache.xml.security.Init.init();
    }

    public static void main( String[] args )
        throws Exception {

        // the secret key to encrypt/decrypt our data
        final byte[] keyBytes = { (byte)0xA2, (byte) 0x15,
            (byte) 0x37, (byte) 0x07, (byte) 0xCB, (byte) 0x62, (byte) 0xC1,
            (byte) 0xD3, (byte) 0xF8, (byte) 0xF1, (byte) 0x97, (byte) 0xDF,
            (byte) 0xD0, (byte) 0x13, (byte) 0x4F, (byte) 0x79, (byte) 0x01,
            (byte) 0x67, (byte) 0x7A, (byte) 0x85, (byte) 0x94, (byte) 0x16,
            (byte) 0x31, (byte) 0x92 };

        final String dataToEncrypt = "Hello World";

        // use DESEde as the key algorithm
        final SecretKeyFactory keyFactory = 
SecretKeyFactory.getInstance("DESEde");
        final KeySpec spec = new DESedeKeySpec(keyBytes);
        final SecretKey secretKey = keyFactory.generateSecret(spec);

        // generate key pair for encrypting/decrypting the shared key
        final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        final KeyPair keyPair = generator.generateKeyPair();

        final Document doc = newDocument();

        // encrypt the secret key with RSA 1.5 and output the EncryptedKey
        XMLCipher cipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5);
        cipher.init(XMLCipher.WRAP_MODE, keyPair.getPublic());
        final EncryptedKey encryptedKey = cipher.encryptKey(doc, secretKey);
        final Element encKeyElement = cipher.martial(encryptedKey);

        writeNode("EncryptedKey:", encKeyElement);

        // encode some data with the secret key
        final Element element = doc.createElement("test");
        element.appendChild(doc.createTextNode(dataToEncrypt));
        doc.appendChild(element);

        cipher = XMLCipher.getInstance(XMLCipher.TRIPLEDES, 
Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
        cipher.init(XMLCipher.ENCRYPT_MODE, secretKey);
        cipher.doFinal(doc, element, false);

        final Element encryptedElement = (Element)doc.getDocumentElement();
        writeNode("\nEncryptedData: ", encryptedElement);

        // get the key back from the EncryptedKey (i.e. don't use the original 
key)
        cipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5);
        cipher.init(XMLCipher.UNWRAP_MODE, keyPair.getPrivate());
        final SecretKey unwrappedKey = 
(SecretKey)cipher.decryptKey(encryptedKey, XMLCipher.RSA_v1dot5);

        if ( unwrappedKey instanceof SecretKeySpec ) {
            final SecretKeySpec sks = (SecretKeySpec)unwrappedKey;
            System.out.println("\nUnwrapped Key: algorithm=" + 
sks.getAlgorithm());
        }
        else {
            System.out.println("\nUnwrapped Key: " + unwrappedKey);
        }

        // and use it to decrypt the element
        cipher = XMLCipher.getInstance(XMLCipher.TRIPLEDES, 
Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
        cipher.init(XMLCipher.DECRYPT_MODE, unwrappedKey);

        // the error occurs here in JDK1.5 because the unwrapped key is marked as 
"RSA" but the
        // decryption algorithm is TripleDES?
        cipher.doFinal(doc, encryptedElement, false);

        writeNode("\nDecrypted: ", doc);
    }


    private static void writeNode( String msg, Node element )
        throws Exception {

        System.out.println(msg);
        final Transformer transformer = 
TransformerFactory.newInstance().newTransformer();
        transformer.transform(new DOMSource(element), new 
StreamResult(System.out));
    }


    private static Document newDocument()
        throws Exception {

        return 
DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
    }
}


Reply via email to