paulwong

          數字簽名

          處理流程:
          1. 假設有一份要傳輸的文檔
          2. 使用某一指定算法將此文檔內容進行計算,得出一字符串,稱為“摘要”
          3. 使用私鑰將此摘要進行加密,得出一字符串,稱為“簽名”
          4. 將私鑰對應的公鑰、摘要和簽名一同發給對方
          5. 對方用公鑰對簽名進行解密,得出一字符串,與摘要對比,看是否符合,如符合,則證明對方身份確認
          6. 使用同一算法再次對文檔進行計算,得出一字符串,和摘要對比,看是否符合,如符合則證明此文檔沒有被改過
          7. 經過5和6的雙重驗證后,則可以確認發文方的身份和此文檔在傳輸過程中沒有被改過,可以使
          發送的文檔<Envelope xmlns="urn:envelope">
              <Item number="130046593231">
                  <Description>Video Game</Description>
                  <Price>10.29</Price>
              </Item>
              <Buyer id="8492340">
                  <Name>My Name</Name>
                  <Address>
                      <Street>One Network Drive</Street>
                      <Town>Burlington</Town>
                      <State>MA</State>
                      <Country>United States</Country>
                      <PostalCode>01803</PostalCode>
                  </Address>
              </Buyer>
          </Envelope>


          添加簽名的程序
          /**
           * Licensed to the Apache Software Foundation (ASF) under one
           * or more contributor license agreements. See the NOTICE file
           * distributed with this work for additional information
           * regarding copyright ownership. The ASF licenses this file
           * to you 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 javax.xml.crypto.dsig.samples;

          import java.io.FileInputStream;
          import java.io.FileOutputStream;
          import java.io.OutputStream;
          import java.security.KeyPair;
          import java.security.KeyPairGenerator;
          import java.security.Provider;
          import java.util.Collections;

          import javax.xml.crypto.dsig.CanonicalizationMethod;
          import javax.xml.crypto.dsig.DigestMethod;
          import javax.xml.crypto.dsig.Reference;
          import javax.xml.crypto.dsig.SignatureMethod;
          import javax.xml.crypto.dsig.SignedInfo;
          import javax.xml.crypto.dsig.Transform;
          import javax.xml.crypto.dsig.XMLSignature;
          import javax.xml.crypto.dsig.XMLSignatureFactory;
          import javax.xml.crypto.dsig.dom.DOMSignContext;
          import javax.xml.crypto.dsig.keyinfo.KeyInfo;
          import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
          import javax.xml.crypto.dsig.keyinfo.KeyValue;
          import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
          import javax.xml.crypto.dsig.spec.TransformParameterSpec;
          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.w3c.dom.Document;

          /**
           * This is a simple example of generating an Enveloped XML 
           * Signature using the JSR 105 API. The resulting signature will look 
           * like (key and signature values will be different):
           *
           * <pre><code>
           *<Envelope xmlns="urn:envelope">
           * <Signature xmlns="
          http://www.w3.org/2000/09/xmldsig#">
           *   <SignedInfo>
           *     <CanonicalizationMethod Algorithm="
          http://www.w3.org/TR/2001/REC-xml-c14n
          -20010315"/>
           *     <SignatureMethod Algorithm="
          http://www.w3.org/2000/09/xmldsig#dsa-sha1"/>
           *     <Reference URI="">
           *       <Transforms>
           *         <Transform Algorithm="
          http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
           *       </Transforms>
           *       <DigestMethod Algorithm="
          http://www.w3.org/2000/09/xmldsig#sha1"/>
           *       <DigestValue>K8M/lPbKnuMDsO0Uzuj75lQtzQI=<DigestValue>
           *     </Reference>
           *   </SignedInfo>
           *   <SignatureValue>
           *     DpEylhQoiUKBoKWmYfajXO7LZxiDYgVtUtCNyTgwZgoChzorA2nhkQ==
           *   </SignatureValue>
           *   <KeyInfo>
           *     <KeyValue>
           *       <DSAKeyValue>
           *         <P>
           *           rFto8uPQM6y34FLPmDh40BLJ1rVrC8VeRquuhPZ6jYNFkQuwxnu/wCvIAMhukPBL
           *           FET8bJf/b2ef+oqxZajEb+88zlZoyG8g/wMfDBHTxz+CnowLahnCCTYBp5kt7G8q
           *           UobJuvjylwj1st7V9Lsu03iXMXtbiriUjFa5gURasN8=
           *         </P>
           *         <Q>
           *           kEjAFpCe4lcUOdwphpzf+tBaUds=
           *         </Q>
           *         <G>
           *           oe14R2OtyKx+s+60O5BRNMOYpIg2TU/f15N3bsDErKOWtKXeNK9FS7dWStreDxo2
           *           SSgOonqAd4FuJ/4uva7GgNL4ULIqY7E+mW5iwJ7n/WTELh98mEocsLXkNh24HcH4
           *           BZfSCTruuzmCyjdV1KSqX/Eux04HfCWYmdxN3SQ/qqw=
           *         </G>
           *         <Y>
           *           pA5NnZvcd574WRXuOA7ZfC/7Lqt4cB0MRLWtHubtJoVOao9ib5ry4rTk0r6ddnOv
           *           AIGKktutzK3ymvKleS3DOrwZQgJ+/BDWDW8kO9R66o6rdjiSobBi/0c2V1+dkqOg
           *           jFmKz395mvCOZGhC7fqAVhHat2EjGPMfgSZyABa7+1k=
           *         </Y>
           *       </DSAKeyValue>
           *     </KeyValue>
           *   </KeyInfo>
           * </Signature>
           *</Envelope>
           * </code></pre>
           
          */
          public class GenEnveloped {

              //
              
          // Synopsis: java GenEnveloped [document] [output]
              
          //
              
          //    where "document" is the name of a file containing the XML document
              
          //    to be signed, and "output" is the name of the file to store the
              
          //    signed document. The 2nd argument is optional - if not specified,
              
          //    standard output will be used.
              
          //
              public static void main(String[] args) throws Exception {

                  // Create a DOM XMLSignatureFactory that will be used to generate the 
                  
          // enveloped signature
                  String providerName = System.getProperty
                      ("jsr105Provider", "org.apache.jcp.xml.dsig.internal.dom.XMLDSigRI");
                  XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM",
                       (Provider) Class.forName(providerName).newInstance());

                  // Create a Reference to the enveloped document (in this case we are
                  
          // signing the whole document, so a URI of "" signifies that) and
                  
          // also specify the SHA1 digest algorithm and the ENVELOPED Transform.
                  Reference ref = fac.newReference
                      ("", fac.newDigestMethod(DigestMethod.SHA1, null),
                       Collections.singletonList
                        (fac.newTransform
                          (Transform.ENVELOPED, (TransformParameterSpec) null)), 
                       nullnull);

                  // Create the SignedInfo
                  SignedInfo si = fac.newSignedInfo
                      (fac.newCanonicalizationMethod
                       (CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, 
                        (C14NMethodParameterSpec) null), 
                       fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
                       Collections.singletonList(ref));

                  // Create a DSA KeyPair
                  KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
                  kpg.initialize(512);
                  KeyPair kp = kpg.generateKeyPair();

                  // Create a KeyValue containing the DSA PublicKey that was generated
                  KeyInfoFactory kif = fac.getKeyInfoFactory();
                  KeyValue kv = kif.newKeyValue(kp.getPublic());

                  // Create a KeyInfo and add the KeyValue to it
                  KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

                  // Instantiate the document to be signed
                  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                  dbf.setNamespaceAware(true);
                  
                  //////////////////////////
                  String xmlPath = "E:/PAUL/WORK/WORDSPACES/WORKSPACE2/xmlsecurity/src/main/java/javax/xml/crypto/dsig/samples/envelope.xml";
                  
                  Document doc = 
                      dbf.newDocumentBuilder().parse(new FileInputStream(xmlPath));

                  // Create a DOMSignContext and specify the DSA PrivateKey and
                  
          // location of the resulting XMLSignature's parent element
                  DOMSignContext dsc = new DOMSignContext
                      (kp.getPrivate(), doc.getDocumentElement());

                  // Create the XMLSignature (but don't sign it yet)
                  XMLSignature signature = fac.newXMLSignature(si, ki);

                  // Marshal, generate (and sign) the enveloped signature
                  signature.sign(dsc);

                  // output the resulting document
                  OutputStream os;
                  if (args.length > 1) {
                     os = new FileOutputStream(args[1]);
                  } else {
                     os = System.out;
                  }

                  TransformerFactory tf = TransformerFactory.newInstance();
                  Transformer trans = tf.newTransformer();
                  trans.transform(new DOMSource(doc), new StreamResult(os));
              }
          }


          添加簽名后的文檔,簽名部份XML的大括號間不能有空格或換行符,否則驗證不通過
          <?xml version="1.0" encoding="UTF-8" standalone="no"?><Envelope xmlns="urn:envelope">
              <Item number="130046593231">
                  <Description>Video Game</Description>
                  <Price>10.29</Price>
              </Item>
              <Buyer id="8492340">
                  <Name>My Name</Name>
                  <Address>
                      <Street>One Network Drive</Street>
                      <Town>Burlington</Town>
                      <State>MA</State>
                      <Country>United States</Country>
                      <PostalCode>01803</PostalCode>
                  </Address>
              </Buyer>
          <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>fc8XkDVq9QKriU7AozXV6v2Prx8=</DigestValue></Reference></SignedInfo><SignatureValue>HUXMONQ6S9e+32KEoRMOWi/PiYqfii3LZ9lFKjZxDvYDuVJC1QAAkVFwRPH4jF7/Dnhi6h6t5+mZ
          QLbFotZa9w==</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>r46mE0A/S1MWifppSCg3e1nwk6PiRJu2UC9eX8egFLU/iyNXlungrt1rbMMYpgrcd9M4pK0CZ4I0
          SVXvQrbukQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue></KeyInfo></Signature></Envelope>


          驗證程序
          /**
           * Licensed to the Apache Software Foundation (ASF) under one
           * or more contributor license agreements. See the NOTICE file
           * distributed with this work for additional information
           * regarding copyright ownership. The ASF licenses this file
           * to you 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 javax.xml.crypto.dsig.samples;

          import java.io.FileInputStream;
          import java.security.Key;
          import java.security.KeyException;
          import java.security.PublicKey;
          import java.security.cert.X509Certificate;
          import java.util.Iterator;
          import java.util.List;

          import javax.xml.crypto.AlgorithmMethod;
          import javax.xml.crypto.KeySelector;
          import javax.xml.crypto.KeySelectorException;
          import javax.xml.crypto.KeySelectorResult;
          import javax.xml.crypto.XMLCryptoContext;
          import javax.xml.crypto.XMLStructure;
          import javax.xml.crypto.dsig.Reference;
          import javax.xml.crypto.dsig.SignatureMethod;
          import javax.xml.crypto.dsig.XMLSignature;
          import javax.xml.crypto.dsig.XMLSignatureFactory;
          import javax.xml.crypto.dsig.dom.DOMValidateContext;
          import javax.xml.crypto.dsig.keyinfo.KeyInfo;
          import javax.xml.crypto.dsig.keyinfo.KeyValue;
          import javax.xml.crypto.dsig.keyinfo.X509Data;
          import javax.xml.parsers.DocumentBuilderFactory;

          import org.w3c.dom.Document;
          import org.w3c.dom.NodeList;

          /**
           * This is a simple example of validating an XML 
           * Signature using the JSR 105 API. It assumes the key needed to
           * validate the signature is contained in a KeyValue KeyInfo. 
           
          */
          public class ApacheValidate {

              //
              
          // Synopsis: java Validate [document]
              
          //
              
          //      where "document" is the name of a file containing the XML document
              
          //      to be validated.
              
          //
              public static void main(String[] args) throws Exception {

                  // Instantiate the document to be validated
                  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                  dbf.setNamespaceAware(true);
                  String filePath = "E:/PAUL/WORK/WORDSPACES/WORKSPACE2/xmlsecurity/src/main/java/javax/xml/crypto/dsig/samples/envelopedSignature.xml";
                  String bigXml = "E:/PAUL/WORK/WORDSPACES/WORKSPACE2/ucp/data/201301_CM_big.xml";
                  
                  Document doc =
                      dbf.newDocumentBuilder().parse(new FileInputStream(bigXml));

                  // Find Signature element
                  NodeList nl = 
                      doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
                  if (nl.getLength() == 0) {
                      throw new Exception("Cannot find Signature element");
                  }

                  // Create a DOM XMLSignatureFactory that will be used to unmarshal the 
                  
          // document containing the XMLSignature 
                  /*String providerName = System.getProperty
                      ("jsr105Provider", "org.apache.jcp.xml.dsig.internal.dom.XMLDSigRI");
                  XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM",
                      (Provider) Class.forName(providerName).newInstance());
          */
                  
                  XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

                  // Create a DOMValidateContext and specify a KeyValue KeySelector
                  
          // and document context
                  DOMValidateContext valContext = new DOMValidateContext
                      (new KeyValueKeySelector(), nl.item(0));
                  
                  // unmarshal the XMLSignature
                  XMLSignature signature = fac.unmarshalXMLSignature(valContext);

                  // Validate the XMLSignature (generated above)
                  boolean coreValidity = signature.validate(valContext); 

                  // Check core validation status
                  if (coreValidity == false) {
                      System.err.println("Signature failed core validation"); 
                      boolean sv = signature.getSignatureValue().validate(valContext);
                      System.out.println("signature validation status: " + sv);
                      // check the validation status of each Reference
                      Iterator i = signature.getSignedInfo().getReferences().iterator();
                      for (int j = 0; i.hasNext(); j++) {
                          boolean refValid = 
                              ((Reference) i.next()).validate(valContext);
                          System.out.println("ref[" + j + "] validity status: " + refValid);
                      }
                  } else {
                      System.out.println("Signature passed core validation");
                  }
              }

              /**
               * KeySelector which retrieves the public key out of the
               * KeyValue element and returns it.
               * NOTE: If the key algorithm doesn't match signature algorithm,
               * then the public key will be ignored.
               
          */
              private static class KeyValueKeySelector extends KeySelector {
                  public KeySelectorResult select(KeyInfo keyInfo,
                                                  KeySelector.Purpose purpose,
                                                  AlgorithmMethod method,
                                                  XMLCryptoContext context)
                      throws KeySelectorException {
                      if (keyInfo == null) {
                          throw new KeySelectorException("Null KeyInfo object!");
                      }
                      SignatureMethod sm = (SignatureMethod) method;
                      List list = keyInfo.getContent();

                      //org.jcp.xml.dsig.internal.dom.DOMX509Data
                      
                      PublicKey pk = null;
                      for (int i = 0; i < list.size(); i++) {
                          XMLStructure xmlStructure = (XMLStructure) list.get(i);
                          if (xmlStructure instanceof KeyValue) {
                              try {
                                  pk = ((KeyValue)xmlStructure).getPublicKey();
                              } catch (KeyException ke) {
                                  throw new KeySelectorException(ke);
                              }
                              // make sure algorithm is compatible with method
                              if (algEquals(sm.getAlgorithm(), pk.getAlgorithm())) {
                                  return new SimpleKeySelectorResult(pk);
                              }
                          }
                          else if(xmlStructure instanceof X509Data)
                          {
                              for (Object data : ((X509Data) xmlStructure).getContent()) {
                                  if (data instanceof X509Certificate) {
                                      pk = ((X509Certificate) data).getPublicKey();
                                      return new SimpleKeySelectorResult(pk);
                                  }
                             }
                          }
                      }
                      throw new KeySelectorException("No KeyValue element found!");
                  }

                  //@@@FIXME: this should also work for key types other than DSA/RSA
                  static boolean algEquals(String algURI, String algName) {
                      if (algName.equalsIgnoreCase("DSA") &&
                          algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) {
                          return true;
                      } else if (algName.equalsIgnoreCase("RSA") &&
                          algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)) {
                          return true;
                      } else if (algName.equalsIgnoreCase("EC") &&
                          algURI.equalsIgnoreCase("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256")) {
                          return true;
                      } else {
                          return false;
                      }
                  }
              }

              private static class SimpleKeySelectorResult implements KeySelectorResult {
                  private PublicKey pk;
                  SimpleKeySelectorResult(PublicKey pk) {
                      this.pk = pk;
                  }

                  public Key getKey() { return pk; }
              }
          }


          參考:
          http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html

          posted on 2013-04-26 16:22 paulwong 閱讀(491) 評論(0)  編輯  收藏 所屬分類: J2SE

          主站蜘蛛池模板: 五家渠市| 渑池县| 麻栗坡县| 张家港市| 肇州县| 阳春市| 乐清市| 剑河县| 绥中县| 西平县| 巨鹿县| 高淳县| 彭山县| 静宁县| 巴林左旗| 象州县| 剑川县| 麻阳| 吉木萨尔县| 桓台县| 唐河县| 石屏县| 连平县| 定州市| 河北区| 宝坻区| 承德县| 准格尔旗| 包头市| 潼关县| 柘城县| 阿拉善盟| 镇雄县| 石屏县| 龙泉市| 青河县| 绥中县| 民权县| 玉门市| 邢台市| 荆门市|