Listing 1.
<purchaseOrder> <Order> <Item>book</Item> <Id>123-958-74598</Id> <Quantity>12</Quantity> </Order> <Payment> <CardId>123654-8988889-9996874</CardId> <CardName>visa</CardName> <ValidDate>12-10-2004</ValidDate> </Payment> </purchaseOrder>
|
注意:我们故意使 清单 1 中的 XML 文件非常简单。这有助于将我们的注意力集中在与加密相关的问题上。用于合作商业或 Web 服务的现实 XML 文件将有类似的结构,但更冗长。WSDL(Web 服务定义语言)和 SOAP(简单对象访问协议)是 B2B 集成中经常使用的基于 XML 的语法。WSDL 和 SOAP 都可使用 XML 加密来提供企业内的安全通信。有关它们的详细信息,请访问 W3C(请参阅 参考资料)。
使用 XML 加密对整个文档加密
XML 加密提供各种选项。 清单 2、 清单 3和 清单 4显示了不同的加密结果。让我们逐个仔细研究它们。
倘若您决定加密 清单 1中的整个 XML 文档,则 清单 2 显示最后所得到的 XML 加密的文件。请注意 <CipherData>
和 <CipherValue>
标记。实际加密的数据作为 <CipherValue>
标记的内容出现。整个 CipherData
元素出现在一个 EncryptedData
元素内。 EncryptedData
元素包含用于加密的 XML 名称空间。例如,加密前的原始数据是 XML 并且 Internet Assigned Numbers Authority(IANA)对 XML 的正式类型定义是 http://www.isi.edu/in-notes/iana/assignments/media-types/text/xml。这作为 Type
属性的值出现。XML 对各种流行的数据格式(如 RTF、PDF 和 JPG)使用 IANA 的类型定义。完整细节,请参阅它们的网站(请参阅 参考资料 )。如果有特殊的应用程序数据类型(可能是属于您公司的内容管理系统特有的 DTD 或 XSD),可以在 EncryptedData
元素的 Type
属性里指定它们。另一个属性 xmlns 指定了用来加密 XML 数据的 XML 加密名称空间。
使用 XML 加密对单个元素加密
您可能只想加密 清单 1 中的一个元素 ― 例如 Payment
元素。在这种情况下, 清单 3中阐明了其结果。比较 清单 2和 清单 3,您将发现下列差异:
- 清单 2只包含 XML 加密的模式,而 清单 3既包含 XML 加密模式又包含来自 清单 1中原始数据的元素。在 清单 3中,XML 加密被嵌入到用户的 XML 中。
- 清单 3 的
<EncryptedData>
中也有一个 Type
属性,但它的值是 http://www.w3.org/2001/04/xmlenc#Element。我们不再使用 IANA 类型;相反,我们使用 XML 加密已指定的类型。
- 请特别注意末尾的片段 #Element,它表示 EncryptedData ― 这代表一个元素。
加密元素的内容
如果您只要加密 清单 1 中元素 CardId
中的内容, 清单 4 就是其结果。这次,我们使用 http://www.w3.org/2001/04/xmlenc#Content 作为 Type
属性的值。每当我们都仅须加密内容时都使用这个值。
加密非 XML 数据
假如您希望通过 XML 加密发送一个 JPEG 文件,那会怎么样呢? 清单 5 是将产生的一个典型文件。按字节序列加密的整个 JPEG 文件将作为 CipherValue
元素的内容出现。请注意, 清单 2和 清单 5 之间唯一的差异: EncryptedData
元素的 Type
属性。 清单 5包含了 JPEG 格式的 IANA 类型。类似地,可以通过提供 IANA 值(参考 IANA 网站,请参阅 参考资料)加密任何格式。
XML 加密的密钥
在清单 1 到 5 中,我们已经演示了加密,而加密就不可能不使用密钥(请参下 公钥、私钥和秘钥)。使用 XML 加密,所有与密钥相关的问题划分成两个部分:
· 密钥的交换(非对称加密)
· 使用预先交换的密钥(对称加密)
这样,用户可以交换密钥并在以后使用它们。
公钥、私钥和秘钥
我们使用了三个与密钥相关的术语(公钥、私钥和秘钥)。尽管这些术语对从事端到端安全性的开发人员而言是众所周知的,但 XML 开发人员可能并不熟悉它们。让我们阐明这些术语:
公钥和私钥:我们成对使用它们。有些算法生成一对公钥和私钥。我们将公钥发送给任何希望与我们交换加密数据的人。使用公钥,我们只能加密有限大小的数据。通信伙伴使用我们的公钥加密数据,然后将加密的数据发送给我们。接着,我们用私钥解密数据。这是非对称加密。
秘钥: 我们使用公钥和私钥来交换秘钥。通常随机生成秘钥。一旦使用非对称加密与通信伙伴交换了秘钥,我们就可以在两端都使用这个秘钥加密数据了。这是对称加密。
用于交换秘钥的非对称密钥
在这个方案中,一方将它的公钥发送给另一方。另一方使用这个公钥加密其秘钥。 清单 6(请求)和 清单 7 (响应)中显示了这种数据交换。我们假设 Imran 和 Ali 分别是相互通信的第一方和第二方。Imran 初始化了公钥交换请求并在名为 KeyValue 的元素中发送了他的公钥。属性 CarriedKeyName
表示所传输密钥的名称。请注意这个结构的根元素是 EncryptedKey
,它包含 ds:KeyInfo
和 ds:KeyValue
元素。 ds: KeyInfo
和 ds:KeyValue
元素属于 XML 数字签名(ds:)名称空间。对于密钥交换 XML 加密完全依赖于 XML 数字签名规范。因此, <ds:EncryptedKey>
和 <ds:KeyValue>
都属于 XML 数字签名规范名称空间。 清单 7是 Ali 发送的响应。 清单 7 中的 CipherValue
元素包含一个新生成的秘钥,它是用第一方的公钥加密的。仔细看清单 6 和清单 7,您将注意到请求和响应都包含 EncryptedKey
元素。 EncryptedKey
元素内的 ds:KeyInfo
和 ds:KeyValue
元素携带着公钥( 清单 6 )。另一方面, EncryptedKey
元素内的 CipherData
和 CipherValue
元素( 清单 7 )将传输(加密的)秘钥。还请注意 EncryptedKey
元素总是包含一个 CarriedKeyName
属性来指定其所携带密钥的名称。
使用我们过去已经交换的密钥
在前一节中,我们交换了一个秘钥。现在我们将使用那个密钥来加密数据。我们将假定 Imran 发送了一条 XML 消息( 清单 8)来响应 清单 7(请回忆 清单 7包含一个名为“Imran Ali”的加密的秘钥)。Imran 将使用他的(Imran 自己的)私钥来解密这个秘钥(因为 Ali 用 Imran 的公钥加密了这个秘钥)。Imran 可以使用这个秘钥并将它放在 清单 8 中的 CipherValue
元素中来加密他打算发送给 Ali 的数据。
清单 8 中的 ds:KeyInfo
元素包含一个 KeyName
元素。这个组合引用了 Imran 用于数据加密的密钥名称。
图 1 是显示用于安全数据交换的 XML 文件的这种交换的可视图。
图 1. 使用 XML 加密进行密钥与数据交换的顺序
在 清单 5和 7 中, CipherData
元素可以出现在 EncryptedData
元素或 EncryptedKey
元素中。我们使用 CipherData
元素来引用加密数据(当它出现在 EncryptedData
元素中时)或加密密钥(当它出现在 EncryptedKey
元素中时)。在清单 5和 7 中,包含实际加密数据的 CipherData
元素中都有一个 CipherValue
子元素。
我们也可以引用外部加密数据或加密密钥。这意味着实际加密数据或密钥将出现在别的地方(可能是因特网上的某个地方),而不是在 XML 加密文件内。在这种情况下,我们将在 CipherData
中使用 CipherReference
而不是 CipherValue
子元素。我们将通过 URI 引用实际加密数据。这在 清单 9中显示。
引用外部 XML 文件中的特定元素
清单 10 说明了引用外部 XML 文件的一个变体。这里我们只引用了 URI 所指向的外部文件的一部分。 CipherReference
元素中有一个 Transforms
子元素。这个 Transforms
元素可以包含许多 Transform
元素,其中每个都将包含单个 XPath 元素。这个 XPath 元素指定一个 XPath 表达式,该表达式引用外部 XML 文档的特定节点。
我们的 API 的 DOM 结构
我们已经演示了如何创建 XML 加密文件以及交换加密数据。现在我们将推荐用于 XML 加密的 Java API 并提供一个样本实现。为达到这个目的,我们将使用 DOM。
我们的 DOM 实现由一组类组成(清单 11 到 16)。 XmlEncryption
类( 清单 11)是其余类的封装器,这意味着我们的 API 用户将只需要与这个类交互。在内部它使用其它类的功能。
清单 11是一个能够生成完整 XML 加密文件的封装器类。
清单 12 创建 EncryptedData
元素。
清单 13 创建 EncryptionMethod
元素。
清单 14 创建 KeyInfo
元素。
清单 15 创建 CipherData
元素。
清单 16包含作为静态整数的算法名称及其作为字符串的相应名称空间。
XmlEncryption
类( 清单 11)包含各种公用 Get/Set 方法。用户将调用 Set 方法来指定加密参数,包括下列:
1. 要加密的文件名称
2. 所产生的 XML 加密文件的名称
3. 加密算法的名称
4. 将用于加密的密钥名称
5. 用于 <EncryptedData>
结构标识的 ID
我们已经通过 main ()
方法演示了 XmlEncryption
类( 清单 11 )的使用。我们在 main ()
方法中创建了这个类的实例。构造器实例化了 DOM,因此所有基本类都将使用同个对象。
如 清单 2 中所示,这个实现只支持整个文件的加密。 EncryptCompleteXmlFile ()
方法将通过按序列调用下列方法完成这个任务:
1. GetEncryptedDataDoc()
返回 EncryptedData
类( 清单 12 )的对象。它包含 EncryptedData
元素的结构。
2. GetEncryptionMethodDoc()
返回 Document 对象,该对象包含对应于 EncryptionMethod
元素的 XML 结构。 GetEncryptionMethodDoc()
使用 EncryptionMethod
类( 清单 13)来创建 XML。
3. GetKeyInfoDoc()
返回 Document
对象,该对象包含对应于 KeyInfo 元素的 XML 结构。 GetKeyInfoDoc()
使用 GenericKeyInfo
类( 清单 14 )的对象来创建 XML。这个类仅提供最小的必需功能(对 KeyName
和 KeyValue
元素的支持),您将通过对 GenericKeyInfo
类的继承来提供完整的功能,其中包含对 X509 证书、PGP 数据等的支持。
4. ReadFile()
取得我们希望加密的数据(整个 XML 文件)。
5. GetEncryptedData()
暂时不做任何事情。我们将在本文的下一部分实现这个方法。它应该创建在步骤 4 中取得的 XML 数据的加密格式。在上一节(Java 密码体系结构)中,我们已经简要地讨论了我们的加密策略。
6. GetCipherDataDoc()
将加密数据作为参数,然后返回包含 CipherData
元素的 Document 对象。 GetCipherDataDoc()
使用 CipherData
类( 清单 12)的对象来创建 XML。
7. 最后,三次调用 EncryptedData
( 清单 15 )对象的 addChild()
方法,该方法将获得步骤 2、3 和 6 的 Document 对象,然后将它们添加到 <EncryptedData>
结构,这是它们所有对象的父类。
8. SaveEncryptedFile()
保存完整的 XML 加密文件。
AlgoNames
( 清单 16)是一个只指定 XML 加密所需要的名称空间声明的助手类。
XmlEncryption
类( 清单 11)也可以作为服务器端组件使用。在本系列的下一部分中,我们将演示它在独立应用程序中以及在服务器端应用程序中的使用。
我们已开发的这组类只执行基于 DOM 的 XML 创建。我们还需要实现密码功能。现在我们将尝试形成一个用于密码支持的策略。出于这个目的,我们需要研究 Java 密码体系结构(Java Cryptographic Architecture(JCA))。
Java 密码体系结构(JCA)
Java 提供对密码术的完整支持。出于这个目的,J2SE 中有几个包,它们涵盖了安全性体系结构的主要特性,如访问控制、签名、证书、密钥对、密钥存储和消息摘要等。
JCA 设计的主要原理是将密码概念从算法实现中分离出来,以便不同的供应商可以在 JCA 框架内提供他们的工具。
JCA 引擎类
JCA 定义了一系列引擎(Engine)类,其中每个引擎提供一种密码功能。例如,MD(消息摘要)算法有几种不同的标准。这些标准的实现各不相同,但在引擎 API 级别,它们都是相同的。不同的供应商可以自由地提供特定算法的实现。
Java 密码扩展(JCE)
所有独立(第三方)供应商的密码算法实现都称为 Java 密码扩展(Java Cryptographic Extension (JCE))。Sun Microsystems 也提供了 JCE 的一种实现。无论何时使用 JCE,都必需将它和 JCA 一起配置。为此,我们需要执行如下操作:
1. 添加 jar 文件的地址以在 CLASSPATH
环境变量中配置供应商(将所有 JCE 实现称为供应商)。
2. 通过编辑 java.security 文件,在您认可的供应商列表中配置供应商。这个文件位于 JavaHome/jre/lib/security 文件夹。下列是指定优先级的语法: security.provider.<n>=<masterClassName>
。这里 n 是优先级号(1、2、3 等等)。 MasterClassName
是引擎类将为特定算法实现调用的主类的名称。供应商文档将指定其主类名称。例如,考虑 java.security 文件中的下列项:
· security.provider.1=sun.security.provider.Sun
· security.provider.2=com.sun.rsajca.Provider
· security.provider.3=com.sun.net.ssl.internal.ssl.Provider
这些项意味着引擎类将按上面提到的顺序搜索任何算法实现。它将执行最先找到的实现。完成这些简单步骤之后,我们完全准备好开始在 XML 加密应用程序中使用 JCA/JCE。
在我们的 XML 加密实现中使用 JCA 和 JCE
封装器类 XmlEncryption
( 清单 11 )中的 GetEncryptedData()
函数是处理所有与 JCA/JCE 相关问题的所在。目前,这个方法仅返回字符串“This is Cipher Data”。我们还没有编写与 JCA/JCE 相关的类。这个方法获得未加密数据,然后将它作为加密字符串返回。在编写了用于 JCA/JCE 的封装器类之后,我们将在这个方法中处理所有与算法和密钥相关的问题。
下一次:在这一系列文章的下一部分中,我们将讨论并实现密码术的细节。我们将演示加密和解密类的工作方式以及它们使用解析逻辑的交互,并展示 Web 服务中 XML 加密的应用程序。
Listing 1.
<purchaseOrder> <Order> <Item>book</Item> <Id>123-958-74598</Id> <Quantity>12</Quantity> </Order> <Payment> <CardId>123654-8988889-9996874</CardId> <CardName>visa</CardName> <ValidDate>12-10-2004</ValidDate> </Payment> </purchaseOrder>
|
Listing 2. Encrypting the entire file
<?xml version='1.0' ?> <EncryptedData xmlns='http://www.w3.org/2001/04/xmlenc#' Type='http://www.isi.edu/in-notes/iana/assignments/media-types/text/xml'> <CipherData> <CipherValue>A23B45C56</CipherValue> </CipherData> </EncryptedData>
|
Listing 3. Encrypting only the <Payment> element
<?xml version='1.0' ?> <PurchaseOrder> <Order> <Item>book</Item> <Id>123-958-74598</Id> <Quantity>12</Quantity> </Order> <EncryptedData Type='http://www.w3.org/2001/04/xmlenc#Element' xmlns='http://www.w3.org/2001/04/xmlenc#'> <CipherData> <CipherValue>A23B45C564587</CipherValue> </CipherData> </EncryptedData> </PurchaseOrder>
|
Listing 4. Encrypting only the content in the CardId element
<?xml version='1.0' ?> <PurchaseOrder> <Order> <Item>book</Item> <Id>123-958-74598</Id> <Quantity>12</Quantity> </Order> <Payment> <CardId> <EncryptedData Type='http://www.w3.org/2001/04/xmlenc#Content' xmlns='http://www.w3.org/2001/04/xmlenc#'> <CipherData> <CipherValue>A23B45C564587</CipherValue> </CipherData> </EncryptedData></CardId> <CardName>visa</CardName> <ValidDate>12-10-2004</CardName> </Payment> </PurchaseOrder>
|
Listing 5. Encrypting arbitrary non-XML data (JPEG)
<?xml version='1.0' ?> <EncryptedData xmlns='http://www.w3.org/2001/04/xmlenc#' Type='http://www.isi.edu/in-notes/iana/assignments/media-types/jpeg' > <CipherData> <CipherValue>A23B45C56</CipherValue> </CipherData> </EncryptedData>
|
Listing 6. One party sends its public key to a second party for key exchange
<?xml version='1.0' ?> <SecureCommunicationDemonstration> <EncryptedKey CarriedKeyName="Muhammad Imran" xmlns='http://www.w3.org/2001/04/xmlenc#'> <ds:KeyInfo xmlns:ds='http://www.w3.org/2000/09/xmldsig#'> <ds:KeyValue>1asd25fsdf2dfdsfsdfds2f1sd23</ds:KeyValue> </ds:KeyInfo> </EncryptedKey> </SecureCommunicationDemonstration>
|
Listing 7. Second party sends back the randomly generated secret key encrypted with public key of first party
<?xml version='1.0' ?> <SecureCommunicationDemonstration> <EncryptedKey CarriedKeyName="Imran Ali" xmlns='http://www.w3.org/2001/04/xmlenc#'> <EncryptionMethod Algorithm= "http://www.w3.org/2001/04/xmlenc#rsa-1_5"/> <CipherData> <CipherValue>xyza21212sdfdsfs7989fsdbc</CipherValue> </CipherData> </EncryptedKey> </SecureCommunicationDemonstration>
|
Listing 8. Data is encrypted with a secret key and placed in the <CipherValue> element
<?xml version='1.0' ?> <<SecureCommunicationDemonstration> <Order> <Item>book</Item> <Id>123-958-74598</Id> <Quantity>12</Quantity> <CardName>Visa</CardName> <ExpDate>10-10-2005</ExpDate>
<EncryptedData Type='http://www.w3.org/2001/04/xmlenc#Element' xmlns='http://www.w3.org/2001/04/xmlenc#'> <EncryptionMethod Algorithm='http://www.w3.org/2001/04/xmlenc#tripledes-cbc '/> <ds:KeyInfo xmlns:ds='http://www.w3.org/2000/09/xmldsig#'> <ds:KeyName>Imran ali</ds:KeyName> </ds:KeyInfo> <CipherData> <CipherValue>A23B45C564587</CipherValue> </CipherData> </EncryptedData> </Order> </SecureCommunicationDemonstration>
|
Listing 9. Using the <CipherReference> element to refer to external encrypted data
<?xml version='1.0' ?> <EncryptedData xmlns='http://www.w3.org/2001/04/xmlenc#' Type='http://www.w3.org/2001/04/xmlenc#Element'> <ds:KeyInfo xmlns:ds='http://www.w3.org/2000/09/xmldsig#'> <ds:KeyName>Imran ali</ds:KeyName> </ds:KeyInfo> <CipherData> <CipherReference URI="www.waxsys.com/secureData/waxFile.txt"/> </CipherData> </EncryptedData>
|
Listing 10. Using the <Transforms> element and XPath to refer to a particular node of the external XML File
<?xml version='1.0' ?> <EncryptedData ID="Enc-Data" xmlns='http://www.w3.org/2001/04/xmlenc#' Type='http://www.w3.org/2001/04/xmlenc#Element' > <CipherReference URI="http://www.waxsys.com/EncFile.xml" > <Transforms xmlns:ds="http://www.w3.org/2000/09/xmldsig#" > <ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> <wax:XPath xmlns:wax="http://www.waxsys.com/xpathNS"> PruchaseOrder/EncryptedData [@Id="Imran-Enc-Data"] </wax:XPath> </ds:Transform> </Transforms> </CipherReference> </EncryptedData>
|
Listing 11. XmlEncryption.java
/* DW/BS 20020204 XmlEncryption.java Listing 11 A wrapper class that can generate complete XML encrypted file. It uses all the other classes. Users of our XML Encryption Engine will only need to interact with this class. */
import java.io.*; import org.w3c.dom.*; import javax.xml.parsers.*; import org.apache.crimson.tree.XmlDocument;
public class XmlEncryption { // Source and Result file names. private String fileSource = null; private String fileResult = null; // Name of Algorithm which will be used to encrypt data. private String algoName = null;
// Name of Secret key which was previously agreed upon // and saved with the given name. private String keyName = null; // Id attribute of Main structure private String encId = null;
// It will be used to get New Document Objects. private DocumentBuilder docBuilder = null;
// Default Constructor public XmlEncryption() { // Create DocumentBuilder object from DocumentBuilderFactory. try { docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); } catch (ParserConfigurationException e){ docBuilder = null; } } // Get the new Document object for DocumentBuilder private Document getNewDocument() { if (docBuilder != null) return docBuilder.newDocument(); else return null; } // Generate Complete XML Encrypted File. public void encryptCompleteXmlFile(){ // Take an Object of EncryptedData Class. // It represents EncryptedData Element. EncryptedData encDataObj = this.getEncryptedDataDoc(this.encId, "DOCUMENT");
// Get XML Structure for EncryptionMehtod element. Document encMethodDoc = this.getEncryptionMethodDoc(this.algoName);
// Get XML Structure for KeyInfo element. Document encKeyInfoDoc = this.getKeyInfoDoc(this.keyName);
// Read the given file data which will be encrypted. String plainData = this.readFile(fileSource);
// Use of JCA/JCE to get encrypted data. String cipherData = this.getEncryptedData(plainData);
// Get XML Structure for CipherData element. Document cipherDataDoc = this.getCipherDataDoc(cipherData);
// Join these XML Structures. encDataObj.addChild(encMethodDoc); encDataObj.addChild(encKeyInfoDoc); encDataObj.addChild(cipherDataDoc); // Now Save this Document as an XML File this.saveEncryptedFile(this.fileResult, encDataObj.getEncData()); }// End encryptCompleteXmlFile() //********** All Set/Get methods to related fields. public void setFileSource(String file) { this.fileSource = file; }// End setFileSource() public String getFileSource() { return this.fileSource; }// End getFileSource()
public void setFileResult(String file) { this.fileResult = file; }// End setFileResult() public String getFileResult() { return this.fileResult; }// End getFileResult() public void setAlgoName(String name) { this.algoName = name; }// End setAlgoName()
public String getAlgoName() { return this.algoName; }// End getAlgoName() public void setKeyName (String key) { this.keyName = key; }// End setKeyName() public String getKeyName() { return this.keyName; }// End getKeyName()
public void setEncId (String id) { this.encId = id; }// End setEncId()
public String getEncId() { return this.encId; }// End setEncId()
//**************
// Reads the given file and returns it as string. public String readFile(String fileName){ String xml = ""; try { FileInputStream in = new FileInputStream(fileName); byte [] data = new byte[in.available()]; in.read(data); xml = new String(data); } catch (IOException e) { } return xml; }// End readFile() // Saves the given document as an XML (Text) file with given name. public void saveEncryptedFile (String fileName, Document doc) { XmlDocument xmlDoc = (XmlDocument)doc; try { OutputStream out = new FileOutputStream(fileName); xmlDoc.write(out); out.close(); } catch (IOException e) { }
}// End saveEncryptedFile() // Returns the EncryptedData Object. public EncryptedData getEncryptedDataDoc(String Id, String encType) { EncryptedData ed = new EncryptedData(this.getNewDocument()); ed.setId(Id); if (encType.equals("DOCUMENT")) ed.setType(AlgoNames.DOCUMENT); return ed; }// End getEncryptedDataDoc()
// Returns the EncryptionMehtod Structure. public Document getEncryptionMethodDoc (String algoName) { EncryptionMethod em = new EncryptionMethod(this.getNewDocument()); if (algoName.equals("TripleDes-cbc")) em.setAlgorithm(AlgoNames.TRIPLE_DES); return em.getEncMethod(); }// End getEncryptionMethodDoc()
// Returns the KeyInfo Structure. public Document getKeyInfoDoc (String keyName) { GenericKeyInfo ki = new GenericKeyInfo(this.getNewDocument(),"ds", AlgoNames.XML_DSIG); ki.setKeyName(keyName); return ki.getKeyInfo(); }// End getKeyInfoDoc() // Returns the CipherData Structure. public Document getCipherDataDoc (String data) { CipherData cd = new CipherData(this.getNewDocument()); cd.setValue(data); return cd.getCipherData(); }// getCipherDataDoc() // In the future, all JCA/JCE related classes will be used here. // It will take plain text and return its encrypted form. // All necessary Infromation about keys and algos will be // taken from the fields representing them. // For the time being it is not doing any thing. public String getEncryptedData(String data) { return "This is Cipher Data"; }// End getEncryptedData() // This main method is only included to demonstrate functionality. public static void main (String args[]) { XmlEncryption xmlEnc = new XmlEncryption(); xmlEnc.setFileSource("Order.xml"); xmlEnc.setFileResult("EncryptedOrder.xml"); xmlEnc.setAlgoName("TripleDes-cbc"); xmlEnc.setKeyName("ImranAli"); xmlEnc.setEncId("Test"); xmlEnc.encryptCompleteXmlFile(); }// End main() }// End Class DemoApplication
|
Listing 12. Authors the EncryptedData element
/* DW/BS 20020204 EncryptedData.java Listing 12 Authors the EncryptedData element which is the parent of all XML Encryption structures except EncryptedData element. */
import org.w3c.dom.*;
public class EncryptedData{ // Element to hold complete XML Structure. Element encData = null; Document doc = null;
// Element will be appended in Document only once. private boolean elementAppendedToDoc = false;
// Default Constructor public EncryptedData(Document document) { doc = document; encData = doc.createElement("EncryptedData"); // Add the namespace attribute encData.setAttribute("xmlns","http://www.w3.org/2001/04/xmlenc#"); }// End EncryptedData()
// Specify the ID of this EncryptedData as there // can be many EncryptedData elements in the same XML file. public void setId(String id){ encData.setAttribute("Id", id); }// End setId() // There can be three types: // 201 for ELEMENT // 202 for CONTENT // 303 for DOCUMENT public void setType(int type){ encData.setAttribute("Type", AlgoNames.getAlgoNSValue(type)); }// end setType()
// If an Arbitrary type is to be Encrypted, specify its mimeType. public void setArbitraryType(String mimeType){ String typeValue = "http://www.isi.edu/in-notes/iana/assignments/media-types/" + mimeType; encData.setAttribute("Type", typeValue); }// End setArbitraryType() // Add any of these XML Documents KeyInfo | CipherData | Transforms | EncryptionMethod. public void addChild(Document document){ NodeList nList = document.getChildNodes();
for (int i=0 ; i<nList.getLength(); i++){ Node tempNode = nList.item(i); // If it is a Root Element if (tempNode.getNodeType() == Node.ELEMENT_NODE) { Node importedNode = (Node)doc.importNode(tempNode, true /* import all childern*/); encData.appendChild((Element)importedNode); return; }// end if (tempNode.getNodeType() == Node.ELEMENT_NODE) }// end for (int i=0 ; i<nList.getLength(); i++) }// End addChild() // Return the complete XML structure as a Document Object. public Document getEncData(){ if (elementAppendedToDoc == false) { doc.appendChild(encData); elementAppendedToDoc = true; } return doc; }// end getEncData() }// End class EncryptedData
|
Listing 13. Authors the EncryptionMethod element
/* DW/BS 20020204 EncryptionMethod.java Listing 13 Authors the EncryptionMethod element. */
import org.w3c.dom.*; import javax.xml.parsers.*;
public class EncryptionMethod{ // Element to hold complete XML Structure. private Element encMethod = null; private Document doc = null;
// Element will be appended in Document only once. private boolean elementAppendedToDoc = false;
// Constructor public EncryptionMethod (Document document) { doc = document; encMethod = doc.createElement("EncryptionMethod"); }// End EncryptionMethod() // Set the name of Algorithm. public void setAlgorithm(int algoNo){ encMethod.setAttribute("Algorithm", AlgoNames.getAlgoNSValue(algoNo)); }// End setAlgorithm() // Get the complete Document Sturcture. public Document getEncMethod() { if (elementAppendedToDoc == false) { doc.appendChild(encMethod); elementAppendedToDoc = true; } return doc; }// End getEncMethod() }// End Class EncryptionMethod
|
Listing 14. Authors the KeyInfo element
/* DW/BS 20020204 GenericKeyInfo.java Listing 14 Authors the KeyInfo element. */
import org.w3c.dom.*;
public class GenericKeyInfo {
// Element to hold complete XML Structure. protected Element keyInfo = null; protected Document doc = null;
// Element will be appended in Document only once. protected boolean elementAppendedToDoc = false;
// Default constructor. public GenericKeyInfo (Document document, String nsQlif, int typeNo) { doc = document; keyInfo = doc.createElement(nsQlif + ":KeyInfo"); // Add the namespace attribute. keyInfo.setAttribute("xmlns:" + nsQlif, AlgoNames.getAlgoNSValue(typeNo)); }// End GenericKeyInfo // Add KeyName child in KeyInfo public void setKeyName(String keyName) { Element tempElem = doc.createElement("KeyName"); tempElem.appendChild(doc.createTextNode(keyName)); keyInfo.appendChild(tempElem); }// End setKeyName() // Add KeyValue child in KeyInfo public void setKeyValue (String keyValue){ Element tempElem = doc.createElement("KeyValue"); tempElem.appendChild(doc.createTextNode(keyValue)); keyInfo.appendChild(tempElem); }// End setKeyValue() // Set retrieval Method URI and and Its type. public void setRetrievalMethod (String uriValue, int typeNo) { Element tempElem = doc.createElement("RetrievalMethod"); tempElem.setAttribute("URI", uriValue); tempElem.setAttribute("Type", AlgoNames.getAlgoNSValue(typeNo)); keyInfo.appendChild(tempElem); }// End setRetrievalMethod() // Return the complete XML structure as a Document Object. public Document getKeyInfo() { if (elementAppendedToDoc == false ) { doc.appendChild(keyInfo); elementAppendedToDoc = true; } return doc; }// End getKeyInfo() } // end class KeyInfo
|
Listing 15. Authors the CipherData element
/* DW/BS 20020204 CipherData.java Listing 15 Authors the CipherData element. */
import org.w3c.dom.*;
public class CipherData { // We will create child elements within this document. private Document doc = null; // The main structure. private Element cipherData = null;
// Element will be appended in Document only once. private boolean elementAppendedToDoc = false; // Constructor public CipherData(Document document){ doc = document; cipherData = doc.createElement("CipherData");
elementAppendedToDoc = false; }// End CipherData()
// Sets the encrypted Data inside CipherValue Child tag. public void setValue(String value){ Element tempElem = doc.createElement("CipherValue"); tempElem.appendChild(doc.createTextNode(value)); cipherData.appendChild(tempElem); }// End setValue()
// Adds CipherReference element inside CipherData element. // Its Attribute URI is passed as parameter. // Transform element is optional. // If want to set only URI then pass NULL in place of transforms Element public void setCipherReference (String uriValue, Element transforms) { Element tempElem = doc.createElement("CipherReference"); tempElem.setAttribute("URI", uriValue); if ( transforms != null ) tempElem.appendChild(transforms); cipherData.appendChild(tempElem); }// End setCipherReference() // Retuns the completed CipherData structure. public Document getCipherData() { if (elementAppendedToDoc == false ) { doc.appendChild(cipherData); elementAppendedToDoc = true; } return doc; }// End getCipherData() }// end Class CipherData
|
Listing 16. AlgoNames.java
/* DW/BS 20020204 AlgoNames.java Listing 16 This class is only for convenience of use. It contains names of Algorithms as static integers and their corresponding namespaces as strings. */
public class AlgoNames {
public static final int TRIPLE_DES = 1; public static final int AES_128 = 2; public static final int AES_256 = 3; public static final int RSA_V1_5 = 4; public static final int RSA_OAEP = 5; public static final int DH = 6; public static final int KW_TRIPLE_DES = 7; public static final int KW_AES_128 = 8; public static final int KW_AES_256 = 9; public static final int SHA1 = 10; public static final int SHA256 = 11;
public static final int XPATH = 100; public static final int BASE_64 = 101; public static final int ENC_KEY = 102; public static final int XML_DSIG = 103;
// Fields to represent what type of Data to be encrypted. public static final int ELEMENT = 201; public static final int CONTENT = 202; public static final int DOCUMENT = 203; public static String getAlgoNSValue(int algoNo){ String algoNS = ""; switch (algoNo){ case TRIPLE_DES : algoNS = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"; break; case AES_128 : algoNS = "http://www.w3.org/2001/04/xmlenc#aes128-cbc"; break; case AES_256 : algoNS = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"; break; case RSA_V1_5 : algoNS = "http://www.w3.org/2001/04/xmlenc#rsa-1_5"; break; case RSA_OAEP : algoNS = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p";break; case DH : algoNS = "http://www.w3.org/2001/04/xmlenc#dh"; break; case KW_TRIPLE_DES:algoNS = "http://www.w3.org/2001/04/xmlenc#kw-tripledes"; break; case KW_AES_128 : algoNS = "http://www.w3.org/2001/04/xmlenc#kw-aes128"; break; case KW_AES_256 : algoNS = "http://www.w3.org/2001/04/xmlenc#kw-aes256"; break; case SHA1 : algoNS = "http://www.w3.org/2000/09/xmldsig#sha1"; break; case SHA256 : algoNS = "http://www.w3.org/2000/09/xmldsig#sha256"; break; case XPATH : algoNS = "http://www.w3.org/TR/1999/REC-xpath-19991116"; break; case BASE_64 : algoNS = "http://www.w3.org/2000/09/xmldsig#base64"; break; case ENC_KEY : algoNS = "http://www.w3.org/2001/04/xmlenc#EncryptedKey"; break; case XML_DSIG : algoNS = "http://www.w3.org/2000/09/xmldsig#"; break; case ELEMENT : algoNS = "http://www.w3.org/2001/04/xmlenc#Element"; break; case CONTENT : algoNS = "http://www.w3.org/2001/04/xmlenc#Content"; break; case DOCUMENT : algoNS = "http://www.isi.edu/in-notes/iana/assignments/media-types/text/xml"; break; } // end switch(algoNo) return algoNS; }// End getAlgoNsValue() }// End Class
|
参考资料