We have a requirement to encrypt request payloads and decrypt responses that follows the W3 standards. I was to get the encryption following what was described here.
Now what needs to be now is the decryption which I find not as straight forward like a reverse of the encryption. What I have searched so far discussed symmetric encryption and decryption and involving just some String values.
This is how the response looks (namespace URLs shortened):
<xenc:EncryptedData Type="xmlenc#Element" xmlns:xenc="xmlenc#">
<xenc:EncryptionMethod Algorithm="xmlenc#tripledes-cbc"/>
<dsig:KeyInfo xmlns:dsig="xmldsig#">
<xenc:EncryptedKey Recipient="name:55bb96ec-...">
<xenc:EncryptionMethod Algorithm="xmlenc#rsa-1_5"/>
<dsig:KeyInfo>
<dsig:KeyName>55bb96ec-....</dsig:KeyName>
</dsig:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>nO6Hic8FxebFy.....</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedKey>
</dsig:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>j9v2IznqpwCunQiZG....</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
Below is what I have so far which is encountering below error. The expectation is that the decrypted XML has the actual response structure with digital signature.
Exception in thread "main" java.security.InvalidKeyException: Wrong key size
at com.sun.crypto.provider.DESedeCrypt.init(DESedeCrypt.java:69)
at com.sun.crypto.provider.CipherBlockChaining.init(CipherBlockChaining.java:93)
at com.sun.crypto.provider.CipherCore.init(CipherCore.java:591)
at com.sun.crypto.provider.DESedeCipher.engineInit(DESedeCipher.java:197)
at javax.crypto.Cipher.implInit(Cipher.java:809)
at javax.crypto.Cipher.chooseProvider(Cipher.java:867)
at javax.crypto.Cipher.init(Cipher.java:1399)
at javax.crypto.Cipher.init(Cipher.java:1330)
at testDecrypt.main(testDecrypt.java:90)
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
//import com.sun.org.apache.xml.internal.security.utils.Base64;
public class testDecrypt {
static {
org.apache.xml.security.Init.init();
}
public static void main(String[] args) throws Exception {
String xmlInput = "ENCRYPTED XML FOLDER\XENC FILE.xml";
String keyStorePW = "PFX password";
String keyStore = "PFX FILE FOLDER\PFX File.pfx";
//build document from input xml file
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(xmlInput);
//load the Private Key from Keystore
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream(keyStore), keyStorePW.toCharArray());
String alias = ks.aliases().nextElement();
PrivateKey privKey = (PrivateKey)ks.getKey(alias, keyStorePW.toCharArray());
System.out.println("Private Key: "+privKey);
//Get the encrypted Key and data element from input xml
NodeList cipherValueNodes = doc.getElementsByTagName("xenc:CipherValue");
Element encKey = null;
Element encData = null;
for(int i = 0; i < cipherValueNodes.getLength(); i++) {
if (i == 0) {
encKey = (Element)cipherValueNodes.item(i);
}
else {
encData = (Element)cipherValueNodes.item(i);
}
}
System.out.println("Encrypted key: "+encKey.getTextContent());
System.out.println("Encrypted data: "+encData.getTextContent());
//Start decryption of encrypted Key using the private key
Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] encryptedKeyBytes = Base64.getDecoder().decode(encKey.getTextContent());
byte[] decryptedKey = cipher.doFinal(encryptedKeyBytes);
DESedeKeySpec desEdeKeySpec = new DESedeKeySpec(decryptedKey);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey key = keyFactory.generateSecret(desEdeKeySpec);
System.out.println("Key size:"+key.getEncoded().length);
//decrypt the encrypted data element using the secrek key
int ivLen = 8;
byte[] ivBytes = new byte[ivLen];
byte[] encryptedDataBytes = Base64.getDecoder().decode(encData.getTextContent());
System.arraycopy(encryptedDataBytes, 0, ivBytes, 0, ivLen);
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipherData = Cipher.getInstance("DESede/CBC/NoPadding");
cipherData.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
String decryptedData = new String(cipher.doFinal(encryptedDataBytes, ivLen, encryptedDataBytes.length - ivLen));
System.out.println("DEcrypted Data: "+decryptedData);
//write the Decrypted XML
File encryptionFile = new File("FILE OUTPUT DIRECTORY\decryptedInfo2.xml");
FileOutputStream f = new FileOutputStream(encryptionFile);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(f);
transformer.transform(source, result);
f.close();
System.out.println(
"Wrote document containing encrypted data to " + encryptionFile.toURI().toURL().toString()
);
}
}