blautenb 2003/11/17 01:27:05
Modified: src/org/apache/xml/security/encryption XMLCipher.java
src/org/apache/xml/security/keys KeyInfo.java
src_unitTests/org/apache/xml/security/test/encryption
BaltimoreEncTest.java XMLCipherTester.java
Log:
Implementation of KeyResolver for EncryptedKey elements
Revision Changes Path
1.16 +67 -18
xml-security/src/org/apache/xml/security/encryption/XMLCipher.java
Index: XMLCipher.java
===================================================================
RCS file:
/home/cvs/xml-security/src/org/apache/xml/security/encryption/XMLCipher.java,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- XMLCipher.java 16 Nov 2003 09:32:07 -0000 1.15
+++ XMLCipher.java 17 Nov 2003 09:27:04 -0000 1.16
@@ -75,6 +75,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Vector;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
@@ -83,6 +84,9 @@
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
+import
org.apache.xml.security.keys.keyresolver.implementations.EncryptedKeyResolver;
+import org.apache.xml.security.keys.keyresolver.KeyResolverException;
+import org.apache.xml.security.keys.keyresolver.KeyResolverSpi;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.EncryptionConstants;
@@ -1190,13 +1194,29 @@
logger.debug("Decrypting key from previously loaded
EncryptedKey...");
- if(_cipherMode != DECRYPT_MODE && _cipherMode != UNWRAP_MODE)
- logger.error("XMLCipher unexpectedly not in DECRYPT_MODE...");
+ if(_cipherMode != UNWRAP_MODE)
+ logger.error("XMLCipher unexpectedly not in UNWRAP_MODE...");
- if (_kek == null) {
- // For now take the easy apprach and just throw
- logger.error("XMLCipher::decryptKey called without a
KEK");
- throw new XMLEncryptionException("Unable to decrypt
without a KEK");
+ if (algorithm == null) {
+ throw new XMLEncryptionException("Cannot decrypt a key
without knowing the algorithm");
+ }
+
+ if (_key == null) {
+
+ logger.debug("Trying to find a KEK via key resolvers");
+
+ KeyInfo ki = encryptedKey.getKeyInfo();
+ if (ki != null) {
+ try {
+ _key = ki.getSecretKey();
+ }
+ catch (Exception e) {
+ }
+ }
+ if (_key == null) {
+ logger.error("XMLCipher::decryptKey called
without a KEK and cannot resolve");
+ throw new XMLEncryptionException("Unable to
decrypt without a KEK");
+ }
}
// Obtain the encrypted octets
@@ -1238,7 +1258,7 @@
Key ret;
try {
- c.init(Cipher.UNWRAP_MODE, _kek);
+ c.init(Cipher.UNWRAP_MODE, _key);
ret = c.unwrap(encryptedBytes, jceKeyAlgorithm,
Cipher.SECRET_KEY);
} catch (InvalidKeyException ike) {
@@ -1253,6 +1273,23 @@
}
+ /**
+ * Decrypt a key from a passed in EncryptedKey structure. This version
+ * is used mainly internally, when the cipher already has an
+ * EncryptedData loaded. The algorithm URI will be read from the
+ * EncryptedData
+ *
+ * @param encryptedKey Previously loaded EncryptedKey that needs
+ * to be decrypted.
+ * @returns a key corresponding to the give type
+ */
+
+ public Key decryptKey(EncryptedKey encryptedKey) throws
+ XMLEncryptionException {
+
+ return decryptKey(encryptedKey,
_ed.getEncryptionMethod().getAlgorithm());
+
+ }
/**
* Removes the contents of a <code>Node</code>.
@@ -1284,12 +1321,6 @@
if(_cipherMode != DECRYPT_MODE)
logger.error("XMLCipher unexpectedly not in DECRYPT_MODE...");
- if (_key == null) {
- // For now take the easy apprach and just throw
- logger.error("XMLCipher::decryptElement called without
a key");
- throw new XMLEncryptionException("Unable to decrypt
without a key");
- }
-
String octets;
try {
octets = new String(decryptToByteArray(element),
"UTF-8");
@@ -1360,13 +1391,31 @@
if(_cipherMode != DECRYPT_MODE)
logger.error("XMLCipher unexpectedly not in DECRYPT_MODE...");
+ EncryptedData encryptedData = _factory.newEncryptedData(element);
+
if (_key == null) {
- // For now take the easy apprach and just throw
- logger.error("XMLCipher::decryptToByteArray called
without a key");
- throw new XMLEncryptionException("Unable to decrypt
without a key");
- }
- EncryptedData encryptedData = _factory.newEncryptedData(element);
+ KeyInfo ki = encryptedData.getKeyInfo();
+
+ if (ki != null) {
+ try {
+ // Add a EncryptedKey resolver
+ ki.registerInternalKeyResolver(
+ new EncryptedKeyResolver(encryptedData.
+
getEncryptionMethod().
+
getAlgorithm(),
+
_kek));
+ _key = ki.getSecretKey();
+ } catch (KeyResolverException kre) {
+ // We will throw in a second...
+ }
+ }
+
+ if (_key == null) {
+ logger.error("XMLCipher::decryptElement called
without a key and unable to resolve");
+ throw new XMLEncryptionException("Unable to
decrypt without a key");
+ }
+ }
// Obtain the encrypted octets
XMLCipherInput cipherInput = new XMLCipherInput(encryptedData);
1.17 +151 -8
xml-security/src/org/apache/xml/security/keys/KeyInfo.java
Index: KeyInfo.java
===================================================================
RCS file:
/home/cvs/xml-security/src/org/apache/xml/security/keys/KeyInfo.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- KeyInfo.java 14 Nov 2003 21:05:41 -0000 1.16
+++ KeyInfo.java 17 Nov 2003 09:27:05 -0000 1.17
@@ -749,19 +749,12 @@
}
/**
- * This method returns a secret (symmetric) key. This is for XML
Encryption.
- *
- */
- public SecretKey getSecretKey() throws KeyResolverException {
- return null;
- }
-
- /**
* This method returns the public key.
*
*
* @throws KeyResolverException
*/
+
public PublicKey getPublicKey() throws KeyResolverException {
PublicKey pk = this.getPublicKeyFromInternalResolvers();
@@ -1064,6 +1057,156 @@
if (cert != null) {
return cert;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * This method returns a secret (symmetric) key. This is for XML
Encryption.
+ *
+ */
+ public SecretKey getSecretKey() throws KeyResolverException {
+ SecretKey sk = this.getSecretKeyFromInternalResolvers();
+
+ if (sk != null) {
+ log.debug("I could find a secret key using the per-KeyInfo key
resolvers");
+
+ return sk;
+ } else {
+ log.debug("I couldn't find a secret key using the per-KeyInfo key
resolvers");
+ }
+
+ sk = this.getSecretKeyFromStaticResolvers();
+
+ if (sk != null) {
+ log.debug("I could find a secret key using the system-wide key
resolvers");
+
+ return sk;
+ } else {
+ log.debug("I couldn't find a secret key using the system-wide key
resolvers");
+ }
+
+ return null;
+ }
+
+ /**
+ * Searches the library wide keyresolvers for Secret keys
+ *
+ *
+ * @throws KeyResolverException
+ */
+
+ SecretKey getSecretKeyFromStaticResolvers() throws KeyResolverException {
+
+ for (int i = 0; i < KeyResolver.length(); i++) {
+ KeyResolver keyResolver = KeyResolver.item(i);
+
+ for (int j = 0;
+ j < this._constructionElement.getChildNodes().getLength();
+ j++) {
+ Node currentChild =
+ this._constructionElement.getChildNodes().item(j);
+
+ if (currentChild.getNodeType() == Node.ELEMENT_NODE) {
+ if (this._storageResolvers.size() == 0) {
+
+ // if we do not have storage resolvers, we verify with null
+ StorageResolver storage = null;
+
+ if (keyResolver.canResolve((Element) currentChild,
+ this.getBaseURI(), storage)) {
+ SecretKey sk =
+ keyResolver.resolveSecretKey((Element) currentChild,
+ this.getBaseURI(),
+ storage);
+
+ if (sk != null) {
+ return sk;
+ }
+ }
+ } else {
+ for (int k = 0; k < this._storageResolvers.size(); k++) {
+ StorageResolver storage =
+ (StorageResolver)
this._storageResolvers.elementAt(k);
+
+ if (keyResolver.canResolve((Element) currentChild,
+ this.getBaseURI(), storage))
{
+ SecretKey sk =
+ keyResolver.resolveSecretKey((Element)
currentChild,
+ this.getBaseURI(),
+ storage);
+
+ if (sk != null) {
+ return sk;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Searches the per-KeyInfo keyresolvers for secret keys
+ *
+ *
+ * @throws KeyResolverException
+ */
+
+ SecretKey getSecretKeyFromInternalResolvers() throws KeyResolverException
{
+
+ for (int i = 0; i < this.lengthInternalKeyResolver(); i++) {
+ KeyResolverSpi keyResolver = this.itemInternalKeyResolver(i);
+
+ log.debug("Try " + keyResolver.getClass().getName());
+
+ for (int j = 0;
+ j < this._constructionElement.getChildNodes().getLength();
+ j++) {
+ Node currentChild =
+ this._constructionElement.getChildNodes().item(j);
+
+ if (currentChild.getNodeType() == Node.ELEMENT_NODE) {
+ if (this._storageResolvers.size() == 0) {
+
+ // if we do not have storage resolvers, we verify with null
+ StorageResolver storage = null;
+
+ if (keyResolver.engineCanResolve((Element) currentChild,
+ this.getBaseURI(),
+ storage)) {
+ SecretKey sk =
+ keyResolver
+ .engineResolveSecretKey((Element) currentChild,
this
+ .getBaseURI(), storage);
+
+ if (sk != null) {
+ return sk;
+ }
+ }
+ } else {
+ for (int k = 0; k < this._storageResolvers.size(); k++) {
+ StorageResolver storage =
+ (StorageResolver)
this._storageResolvers.elementAt(k);
+
+ if (keyResolver.engineCanResolve((Element) currentChild,
+ this.getBaseURI(),
+ storage)) {
+ SecretKey sk = keyResolver
+ .engineResolveSecretKey((Element) currentChild,
this
+ .getBaseURI(), storage);
+
+ if (sk != null) {
+ return sk;
}
}
}
1.9 +14 -4
xml-security/src_unitTests/org/apache/xml/security/test/encryption/BaltimoreEncTest.java
Index: BaltimoreEncTest.java
===================================================================
RCS file:
/home/cvs/xml-security/src_unitTests/org/apache/xml/security/test/encryption/BaltimoreEncTest.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- BaltimoreEncTest.java 16 Nov 2003 09:20:32 -0000 1.8
+++ BaltimoreEncTest.java 17 Nov 2003 09:27:05 -0000 1.9
@@ -66,6 +66,7 @@
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.KeyFactory;
+import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.Key;
import javax.crypto.SecretKey;
@@ -86,7 +87,11 @@
import org.apache.xml.security.keys.content.x509.XMLX509Certificate;
import org.apache.xml.security.keys.content.KeyName;
import org.apache.xml.security.keys.content.X509Data;
+import org.apache.xml.security.keys.keyresolver.KeyResolverException;
+import org.apache.xml.security.keys.keyresolver.KeyResolver;
+import org.apache.xml.security.keys.storage.StorageResolver;
import org.apache.xml.security.keys.KeyInfo;
+import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.XMLUtils;
import org.apache.xml.serialize.DOMSerializer;
import org.apache.xml.serialize.Method;
@@ -220,9 +225,12 @@
KeyFactory.getInstance("RSA");
rsaKey = keyFactory.generatePrivate(pkcs8Spec);
- // Initialise the library and get out of here
+ // Initialise the library
org.apache.xml.security.Init.init();
+
+ // Register our key resolver
+
KeyResolver.register("org.apache.xml.security.test.encryption.BobKeyResolver");
}
/**
@@ -536,6 +544,7 @@
Key key = findKey(encryptedData);
cipher.init(XMLCipher.DECRYPT_MODE, key);
+
byte[] dd = cipher.decryptToByteArray(ee);
return dd;
@@ -551,7 +560,7 @@
*/
public SecretKey mapKeyName(String name) throws Exception {
-
+ /*
if (name.equals("bob")) {
// Bob is a DESEDE key
@@ -564,6 +573,7 @@
return key;
}
+ */
if (name.equals("job")) {
// Jeb is a AES-128 key
@@ -645,8 +655,7 @@
}
if (kek != null) {
XMLCipher cipher = XMLCipher.getInstance();
- cipher.init(XMLCipher.DECRYPT_MODE, null);
- cipher.setKEK(kek);
+ cipher.init(XMLCipher.UNWRAP_MODE, kek);
key = cipher.decryptKey(encryptedKey,
encryptedData.
getEncryptionMethod().
@@ -723,4 +732,5 @@
}
return (baos.toString());
}
+
}
1.8 +79 -11
xml-security/src_unitTests/org/apache/xml/security/test/encryption/XMLCipherTester.java
Index: XMLCipherTester.java
===================================================================
RCS file:
/home/cvs/xml-security/src_unitTests/org/apache/xml/security/test/encryption/XMLCipherTester.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- XMLCipherTester.java 16 Nov 2003 09:20:32 -0000 1.7
+++ XMLCipherTester.java 17 Nov 2003 09:27:05 -0000 1.8
@@ -158,10 +158,10 @@
/**
* Test encryption using a generated AES 128 bit key that is
- * encrypted using a AES 192 bit key. Then reverse
+ * encrypted using a AES 192 bit key. Then reverse using the KEK
*/
- public void testAES128ElementAES192KWCipher() {
+ public void testAES128ElementAES192KWCipherUsingKEK() {
Document d = document(); // source
Document ed = null;
@@ -182,7 +182,7 @@
// Generate a traffic key
KeyGenerator keygen = KeyGenerator.getInstance("AES");
- keygen.init(192);
+ keygen.init(128);
Key key = keygen.generateKey();
cipher = XMLCipher.getInstance(XMLCipher.AES_192_KeyWrap);
@@ -209,8 +209,78 @@
ee = (Element)
ed.getElementsByTagName("xenc:EncryptedData").item(0);
cipher = XMLCipher.getInstance(XMLCipher.AES_128);
cipher.init(XMLCipher.DECRYPT_MODE, null);
- EncryptedData encryptedData =
cipher.loadEncryptedData(ed, ee);
+ cipher.setKEK(kek);
+ dd = cipher.doFinal(ed, ee);
+
+ target = toString(dd);
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ Assert.assertEquals(source, target);
+ }
+
+
+ /**
+ * Test encryption using a generated AES 192 bit key that is
+ * encrypted using a 3DES key. Then reverse by decrypting
+ * EncryptedKey by hand
+ */
+
+ public void testAES192ElementAES256KWCipher() {
+
+ Document d = document(); // source
+ Document ed = null;
+ Document dd = null;
+ Element e = (Element)
d.getElementsByTagName(element()).item(index());
+ Element ee = null;
+
+ String source = null;
+ String target = null;
+
+ try {
+
+ source = toString(d);;
+
+ // Set up a Key Encryption Key
+ byte[] bits192 = "abcdefghijklmnopqrstuvwx".getBytes();
+ DESedeKeySpec keySpec = new DESedeKeySpec(bits192);
+ SecretKeyFactory keyFactory =
SecretKeyFactory.getInstance("DESede");
+ Key kek = keyFactory.generateSecret(keySpec);
+
+ // Generate a traffic key
+ KeyGenerator keygen = KeyGenerator.getInstance("AES");
+ keygen.init(192);
+ Key key = keygen.generateKey();
+
+ cipher = XMLCipher.getInstance(XMLCipher.TRIPLEDES_KeyWrap);
+ cipher.init(XMLCipher.WRAP_MODE, kek);
+ EncryptedKey encryptedKey = cipher.encryptKey(d, key);
+
+ // encrypt
+ cipher = XMLCipher.getInstance(XMLCipher.AES_192);
+ cipher.init(XMLCipher.ENCRYPT_MODE, key);
+ EncryptedData builder = cipher.getEncryptedData();
+
+ KeyInfo builderKeyInfo = builder.getKeyInfo();
+ if (builderKeyInfo == null) {
+ builderKeyInfo = new KeyInfo(d);
+ builder.setKeyInfo(builderKeyInfo);
+ }
+
+ builderKeyInfo.add(encryptedKey);
+
+ ed = cipher.doFinal(d, e);
+ //decrypt
+ key = null;
+ ee = (Element)
ed.getElementsByTagName("xenc:EncryptedData").item(0);
+ cipher = XMLCipher.getInstance();
+ cipher.init(XMLCipher.DECRYPT_MODE, null);
+
+ EncryptedData encryptedData =
cipher.loadEncryptedData(ed, ee);
+
if(encryptedData == null) {
System.out.println("ed is null");
}
@@ -220,16 +290,15 @@
EncryptedKey ek =
encryptedData.getKeyInfo().itemEncryptedKey(0);
if (ek != null) {
- XMLCipher keyCipher =
XMLCipher.getInstance(XMLCipher.AES_128);
+ XMLCipher keyCipher = XMLCipher.getInstance();
keyCipher.init(XMLCipher.UNWRAP_MODE, kek);
- keyCipher.setKEK(kek);
key = keyCipher.decryptKey(ek,
encryptedData.getEncryptionMethod().getAlgorithm());
}
- cipher.init(XMLCipher.DECRYPT_MODE, key);
- XMLCipher cipher3 =
XMLCipher.getInstance(XMLCipher.AES_128);
- cipher3.init(XMLCipher.WRAP_MODE, null);
- dd = cipher.doFinal(ed, ee);
+ // Create a new cipher just to be paranoid
+ XMLCipher cipher3 = XMLCipher.getInstance();
+ cipher3.init(XMLCipher.DECRYPT_MODE, key);
+ dd = cipher3.doFinal(ed, ee);
target = toString(dd);
} catch (Exception ex) {
@@ -238,7 +307,6 @@
Assert.assertEquals(source, target);
}
-
public void testTrippleDesElementCipher() {
Document d = document(); // source