【问题标题】:Create PrivateKey and PublicKey having a byte array encoded in base 64创建具有以 base 64 编码的字节数组的私钥和公钥
【发布时间】:2012-01-17 01:59:13
【问题描述】:

我有 byte[] 和我的私钥 (llave) 和一个 byte[] 和我的公钥 (certificado=.

我需要将这两个值分别转换为 PrivateKeyPublicKey 对象,以便以后使用它们对 xml 文档进行数字签名。

我试过KeyStore,但我做不到。我还尝试使用KeyFactory 使用以下代码:

import java.io.StringWriter;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
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.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class GeneraXMLCancelacion {
public static void main (String [] args) {
    byte[] certificado = args[0].getBytes();
    byte[] llave = args[1].getBytes();
    String uuids = args[2];
    String rfc = args[3];
    String fecha = args[4];

    String [] uuid = uuids.split("/");

    //GENERAR XML
    try {
        //Crear un document XML vacío
        DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
        dbfac.setNamespaceAware(true);
        DocumentBuilder docBuilder;
        docBuilder = dbfac.newDocumentBuilder();
        Document doc = docBuilder.newDocument();
        doc.setXmlVersion("1.0");
        doc.setXmlStandalone(true);

        Element cancelacion = doc.createElementNS("http://cancelacfd.sat.gob.mx","Cancelacion");
        cancelacion.setAttribute("RfcEmisor", rfc);
        cancelacion.setAttribute("Fecha", fecha);
        doc.appendChild(cancelacion);

        Element folios = doc.createElementNS("http://cancelacfd.sat.gob.mx", "Folios");
        cancelacion.appendChild(folios);
        for (int i=0; i<uuid.length; i++) {
            Element u = doc.createElementNS("http://cancelacfd.sat.gob.mx","UUID");
            u.setTextContent(uuid[i]);
            folios.appendChild(u);
        }

        //create a keyfactory - use whichever algorithm and provider
        KeyFactory kf = KeyFactory.getInstance("DSA");
        //for private keys use PKCS8EncodedKeySpec; for public keys use X509EncodedKeySpec
        PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(llave);
        PrivateKey privateKey = kf.generatePrivate(ks);
        X509EncodedKeySpec x = new X509EncodedKeySpec(certificado);
        PublicKey publicKey = kf.generatePublic(x);


        DOMSignContext dsc = new DOMSignContext (privateKey, doc.getDocumentElement()); 
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

        Reference ref = fac.newReference ("", fac.newDigestMethod(DigestMethod.SHA1, null), 
                    Collections.singletonList
                    (fac.newTransform(Transform.ENVELOPED,
                    (TransformParameterSpec) null)), null, null);
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        KeyValue kv = kif.newKeyValue(publicKey);
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv)); 

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

        KeyInfoFactory kif2 = fac.getKeyInfoFactory();
        KeyValue kv2 = kif2.newKeyValue(publicKey);
        KeyInfo ki2 = kif.newKeyInfo(Collections.singletonList(kv)); 

        XMLSignature signature = fac.newXMLSignature(si, ki);

        signature.sign(dsc);

        //IMPRIMIR EL DOCUMENTO XML
        TransformerFactory transfac = TransformerFactory.newInstance();
        Transformer trans = transfac.newTransformer();
        trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
        trans.setOutputProperty(OutputKeys.VERSION, "1.0");
        trans.setOutputProperty(OutputKeys.INDENT, "yes");

        //CREAR STRING DEL ARBOL XML
        StringWriter sw = new StringWriter();
        StreamResult result = new StreamResult(sw);
        DOMSource source = new DOMSource(doc);
        trans.transform(source, result);
        String xmlString = sw.toString();
        System.out.println(xmlString);
    } catch (ParserConfigurationException e) {
        e.printStackTrace();
    } catch (TransformerConfigurationException e) {
        e.printStackTrace();
    } catch (TransformerException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }

}
}

运行程序时出现此错误:

java.security.spec.InvalidKeySpecException: Inappropriate key specification: invalid key format
at sun.security.provider.DSAKeyFactory.engineGeneratePrivate(Unknown Source)
at java.security.KeyFactory.generatePrivate(Unknown Source)
at vital.cancelaciones.GeneraXMLCancelacion.main(GeneraXMLCancelacion.java:85)

第 85 行对应:

PrivateKey privateKey = kf.generatePrivate(ks);

如果有人有更好的解决方案,我会很感激你的帮助。

【问题讨论】:

  • GeneraXMLCancelacion.java 文件的第 85 行是什么代码?您可以将SSCCE 添加到您的帖子中吗?
  • 我已经编辑了代码以包含所有内容
  • 您应该将所有导入添加到您的代码中。没有它们,很难猜出您正在使用哪些类。
  • 尝试注释第85行。之后编译成功了吗?
  • 尝试使用X509EncodedKeySpec 而不是PKCS8EncodedKeySpec

标签: java encryption public-key private-key


【解决方案1】:

我知道我有一个类似的代码,它与你的类似:

 public KeyPair createKeyPair(byte[] encodedPrivateKey, byte[] encodedPublicKey) {
    try {
        EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
        KeyFactory generator = KeyFactory.getInstance(ASYM_ALGORITHM);
        PrivateKey privateKey = generator.generatePrivate(privateKeySpec);

        EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedPublicKey);
        PublicKey publicKey = generator.generatePublic(publicKeySpec);
        return new KeyPair(publicKey, privateKey);
    } catch (Exception e) {
        throw new IllegalArgumentException("Failed to create KeyPair from provided encoded keys", e);
    }
}

我认为键的字节数组是错误的。如何将它传递给 main 方法?

【讨论】:

  • 字节数组存储在数据库中,我从中获取这些记录,将它们传递给 main 方法并尝试创建键。我在 Visual Basic 中使用了相同的字符串,并且加密算法工作正常。我不知道为什么Java不认为它是一个有效的字节数组...
  • 在这种情况下,字符串可能以不同的字符集编码。尝试使用显式字符集将字节数组转换为字符串。例如args[1].getBytes("UTF8");
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多