简体   繁体   English

如何在服务器端使用Java验证Windows Phone应用程序内购买?

[英]How to validate windows phone in-app purchase with Java on server side?

According to the example: http://code.msdn.microsoft.com/wpapps/In-app-purchase-receipt-c3e0bce4 根据示例: http : //code.msdn.microsoft.com/wpapps/In-app-purchase-receipt-c3e0bce4

The xml file should be validated is: 验证的xml文件为:

<?xml version="1.0"?>
<Receipt Version="1.0" CertificateId="A656B9B1B3AA509EEA30222E6D5E7DBDA9822DCD" xmlns="http://schemas.microsoft.com/windows/2012/store/receipt">
<ProductReceipt PurchasePrice="$20.89" PurchaseDate="2012-11-30T21:32:07.096Z" Id="2f9c5c8f-3e1d-4fc7-a871-ac58f7e78053" AppId="3ec6cd9a-ca82-4d38-bfdf-ecafdb35a738" ProductId="Test" ProductType="Consumable" PublisherDeviceId="Test" MicrosoftProductId="59ef70aa-7099-4679-889e-f21919bfd2c6" />
<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/2001/04/xmldsig-more#rsa-sha256" />
  <Reference URI="">
    <Transforms>
      <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
    </Transforms>
    <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
    <DigestValue>FyFb1HGm+yeOIjt18M6TPD4Qzeu469vwDbQs7w72mdA=</DigestValue>
  </Reference>
</SignedInfo>    
 <SignatureValue>noct5CYBtRwBxVxkUeZIzeDyruLGVBqBMuFuBytpouPLACnQ5dbzdRvWX4XN67IUo0J2FW8DoYcMbf3sAS+PeKKV8SLnU+l8K1hWEbbbugHZezStTzwwkYcZuCTnAk7BYO0aiZWuXm9GiZGT9iyXsYtU1/u87L+llnVibU/m7gV8tD3vG0tVkjzV20C8666mHUsY/jxeq3ed7YY9CT0SDrh5PeL4ESaopBLcncHo/e6lcjyoKbO3e6YuIpsi8DVueeKNhpTlwa5yc0O3qzc5SGnT4Kbhj9NBEXf15/oTaLlg7lJhnQZ0mY+yR8vc4D0SkqD6e5Uc4u64hnu+g3Hphg==</SignatureValue>
</Signature>
</Receipt>

And I can get pulbic key from .cer file: 我可以从.cer文件中获取pulbic密钥:

<Modulus>29AnpbVajjiCYsDRoAK+2dCuKwGLBwmtaEhTyV7aJM9d+G4tp3ifGxyCgJ09JMGt8VYlMcKd/jmXdrdj7IQ79LnGeXbrOlgp7gMPzB1QKHYC0DKmIinjO1UyIt0tbN4lf+umPCj+4x9wphNlwlzkGnvm0FLshrE4rdEnFO/jKHzg6DYbzjbOeJ/ytVlZ3LdsFgaZ/BhgEvpdpszhdI12zEo7c+8Liu+xnsnRvsfaWi7hyMgrKO7Yzqr/5b6JeSCF9FZwuRtrwunVkejJDS+Rcy157ErkIKGBFGVz5VyYbJr+qMsnp2j9D6WCWXAiy1YtS9oXFaPAdgyBINyN7fHIfw==</Modulus>
<Exponent>AQAB</Exponent>

I want to do the validation on my java server. 我想在我的Java服务器上进行验证。 I got a sample code here: http://docs.oracle.com/javase/7/docs/technotes/guides/security/xmldsig/Validate.java . 我在这里获得了示例代码: http : //docs.oracle.com/javase/7/docs/technotes/guides/security/xmldsig/Validate.java Then I made some small changes of the xml file according to: Validate XML signature JAVA 然后,根据以下内容对xml文件进行了一些小的更改: 验证XML签名JAVA

<?xml version="1.0"?>
<Receipt Version="1.0" CertificateId="A656B9B1B3AA509EEA30222E6D5E7DBDA9822DCD" xmlns="http://schemas.microsoft.com/windows/2012/store/receipt">
 <ProductReceipt PurchasePrice="$20.89" PurchaseDate="2012-11-30T21:32:07.096Z" Id="2f9c5c8f-3e1d-4fc7-a871-ac58f7e78053" AppId="3ec6cd9a-ca82-4d38-bfdf-ecafdb35a738" ProductId="Test" ProductType="Consumable" PublisherDeviceId="Test" MicrosoftProductId="59ef70aa-7099-4679-889e-f21919bfd2c6" />
<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/2001/04/xmldsig-more#rsa-sha256" />
  <Reference URI="">
    <Transforms>
      <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
    </Transforms>
    <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
    <DigestValue>FyFb1HGm+yeOIjt18M6TPD4Qzeu469vwDbQs7w72mdA=</DigestValue>
  </Reference>
</SignedInfo>

<SignatureValue>noct5CYBtRwBxVxkUeZIzeDyruLGVBqBMuFuBytpouPLACnQ5dbzdRvWX4XN67IUo0J2FW8DoYcMbf3sAS+PeKKV8SLnU+l8K1hWEbbbugHZezStTzwwkYcZuCTnAk7BYO0aiZWuXm9GiZGT9iyXsYtU1/u87L+llnVibU/m7gV8tD3vG0tVkjzV20C8666mHUsY/jxeq3ed7YY9CT0SDrh5PeL4ESaopBLcncHo/e6lcjyoKbO3e6YuIpsi8DVueeKNhpTlwa5yc0O3qzc5SGnT4Kbhj9NBEXf15/oTaLlg7lJhnQZ0mY+yR8vc4D0SkqD6e5Uc4u64hnu+g3Hphg==</SignatureValue>
<KeyInfo>
<X509Data>  <X509Certificate>MIIDFDCCAgCgAwIBAgIQrih3cQuSeL1CgpLFusfJsTAJBgUrDgMCHQUAMB8xHTAbBgNVBAMTFElhcFJlY2VpcHRQcm9kdWN0aW9uMB4XDTEyMDIxNzAxMTYyNFoXDTM5MTIzMTIzNTk1OVowHzEdMBsGA1UEAxMUSWFwUmVjZWlwdFByb2R1Y3Rpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDb0CeltVqOOIJiwNGgAr7Z0K4rAYsHCa1oSFPJXtokz134bi2neJ8bHIKAnT0kwa3xViUxwp3+OZd2t2PshDv0ucZ5dus6WCnuAw/MHVAodgLQMqYiKeM7VTIi3S1s3iV/66Y8KP7jH3CmE2XCXOQae+bQUuyGsTit0ScU7+MofODoNhvONs54n/K1WVnct2wWBpn8GGAS+l2mzOF0jXbMSjtz7wuK77GeydG+x9paLuHIyCso7tjOqv/lvol5IIX0VnC5G2vC6dWR6MkNL5FzLXnsSuQgoYEUZXPlXJhsmv6oyyenaP0PpYJZcCLLVi1L2hcVo8B2DIEg3I3t8ch/AgMBAAGjVDBSMFAGA1UdAQRJMEeAEHGLK3BRpCWDa2vU50kI73ehITAfMR0wGwYDVQQDExRJYXBSZWNlaXB0UHJvZHVjdGlvboIQrih3cQuSeL1CgpLFusfJsTAJBgUrDgMCHQUAA4IBAQC4jmOu0H3j7AwVBvpQzPMLBd0GTimBXmJw+nruE+0Hh/0ywGTFNE+KcQ21L4v+IuP8iMh3lpOcPb23ucuaoNSdWi375/KxrW831dbh+goqCZP7mWbxpnSnFnuV+R1VPsQjdS+0tg5gjDKNMSx/2fH8krLAkidJ7rvUNmtEWMeVNk0/ZM/ECinobMSSwbqUuc9Qql9T1epe+xv34a6eek+m4W0VXnLSuKhQS5jdILsyeJWHROZF5mrh3DQuS0Ll5FzKmJxHf0hyXAo03SSA+x3JphAU4oYbkE9nRTU1tR6iq1D9ZxfQmvzmIbMfyJ/y89PLs/ewHopSK7vQmGFjfjIl</X509Certificate></X509Data>
    <KeyValue>
    <RSAKeyValue>
        <Modulus>29AnpbVajjiCYsDRoAK+2dCuKwGLBwmtaEhTyV7aJM9d+G4tp3ifGxyCgJ09JMGt8VYlMcKd/jmXdrdj7IQ79LnGeXbrOlgp7gMPzB1QKHYC0DKmIinjO1UyIt0tbN4lf+umPCj+4x9wphNlwlzkGnvm0FLshrE4rdEnFO/jKHzg6DYbzjbOeJ/ytVlZ3LdsFgaZ/BhgEvpdpszhdI12zEo7c+8Liu+xnsnRvsfaWi7hyMgrKO7Yzqr/5b6JeSCF9FZwuRtrwunVkejJDS+Rcy157ErkIKGBFGVz5VyYbJr+qMsnp2j9D6WCWXAiy1YtS9oXFaPAdgyBINyN7fHIfw==</Modulus>
        <Exponent>AQAB</Exponent>
    </RSAKeyValue>
    </KeyValue>
</KeyInfo>
</Signature>
</Receipt>

But the validation failed. 但是验证失败。 I cannot find a solution. 我找不到解决方法。 Plz help. 请帮助。

My java code is below: 我的Java代码如下:

import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.SignatureMethodParameterSpec;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
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 ValidateXMLwithCertificate {

//
// 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);
    Document doc =
        dbf.newDocumentBuilder().parse(new FileInputStream("./ReceiptSHA256.xml"));
    // Find Signature element
    NodeList nl =
        doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
    if (nl.getLength() == 0) {
        throw new Exception("Cannot find Signature element");
    }
    NodeList nl2 =
            doc.getElementsByTagNameNS(XMLSignature.XMLNS, "KeyInfo");
        if (nl2.getLength() == 0) {
            throw new Exception("Cannot find KeyInfo element");
        }
    // Create a DOM XMLSignatureFactory that will be used to unmarshal the
    // document containing the XMLSignature
    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 {

        System.out.println(keyInfo + " " + method);


        if (keyInfo == null) {
            throw new KeySelectorException("Null KeyInfo object!");
        }

        SignatureMethod sm = (SignatureMethod) method;
        List list = keyInfo.getContent();

        for (int i = 0; i < list.size(); i++) {
            XMLStructure xmlStructure = (XMLStructure) list.get(i);
            if (xmlStructure instanceof KeyValue) {
                PublicKey pk = null;
                try {
                    pk = ((KeyValue)xmlStructure).getPublicKey();
                    System.out.println(pk);
                } catch (KeyException ke) {
                    throw new KeySelectorException(ke);
                }
                System.out.println(sm.getAlgorithm() + " -------- " +  pk.getAlgorithm());
                // make sure algorithm is compatible with method
                if (algEquals(sm.getAlgorithm(), pk.getAlgorithm())) {
                    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) {

        XMLSignatureFactory factory = XMLSignatureFactory.getInstance();
        SignatureMethod sm = null;
        try {
            sm = 
                    factory.newSignatureMethod
                        ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", 
                         (SignatureMethodParameterSpec) null);
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("algURI:" + algURI + " algName:" + algName + " SHa1:" + sm.getAlgorithm());
        if (algName.equalsIgnoreCase("DSA") &&
            algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) {
            return true;
        } else if (algName.equalsIgnoreCase("RSA") &&
                   algURI.equalsIgnoreCase(sm.getAlgorithm())) {
            System.out.println("will return true");
            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; }
}
}

最后,我删除了“>”和“ <”之间的所有空格或“ \\ n”后,验证成功。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM