我的私钥(llave)为byte[]
,公钥(certificado =。)为byte[]
。
我需要分别在PrivateKey
和PublicKey
对象中转换这两个值,以便以后使用它们对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);
如果有人有更好的解决方案,我们将不胜感激。
最佳答案
我有一个类似的代码,我知道它可以工作,并且类似于您的代码:
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方法?
关于java - 创建具有以base 64编码的字节数组的私钥和公钥,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8451205/