Apache Santuario (XML-Sicherheit) (http://santuario.apache.org/) scheint de facto das Signaturzeichen für XML in Java zu sein.
Zum Signieren benötigen Sie zunächst ein Zertifikat und einen privaten Schlüssel. Bitte bereiten Sie sich im Voraus vor. Als ich den privaten Schlüssel mit pem vorbereitet habe, wurde er nicht erkannt, daher werde ich den privaten Schlüssel im Format pkcs # 8 belassen. Es gibt vielleicht eine Möglichkeit, das PEM direkt zu lesen, aber hier werden wir den Schlüssel konvertieren.
$ openssl pkcs8 -in xxx.pem -topk8 -nocrypt -outform DER -out mypriv.key
Lesen Sie das Zertifikat und den privaten Schlüssel wie folgt: Oh, der Code verwendet auch Lombok.
public static X509Certificate loadCert(InputStream certFile) throws CertificateException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
return (X509Certificate)cf.generateCertificate(certFile);
}
public static PrivateKey loadPrivateKey(InputStream privateKey) throws IOException, GeneralSecurityException {
val buf = readPrivateKey(privateKey);
val keySPec = new PKCS8EncodedKeySpec(buf);
return KeyFactory.getInstance("RSA").generatePrivate(keySPec);
}
private static byte[] readPrivateKey(InputStream in) throws IOException {
byte[] data = new byte[in.available()];
in.read(data);
return data;
}
Nachdem Sie Ihr Zertifikat und Ihren privaten Schlüssel bereit haben, signieren Sie das XML.
Erstellen Sie zuerst ein zu signierendes Objekt. Geben Sie den URI und den Signaturalgorithmus für das XML-Dokumentobjekt an, das beim Erstellen des Objekts und seiner Datei verarbeitet werden soll. Danach füge ich ein Element hinzu, um das ursprüngliche XML zu signieren.
val sig = new XMLSignature(doc, "file:/test.xml", XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
doc.getDocumentElement().appendChild(sig.getElement())
Übrigens test.xml
<?xml version="1.0" encoding="UTF-8"?>
<elem1>
<elemt2>xxx</elem2>
</elem1>
Registrieren Sie als Nächstes den Resource Resolver. Dies ist der ResourceResolver, der dann das Objekt zum Abrufen der zu verdaulichen Elemente und des Inhalts einer anderen Datei ist. Der ResourceResolver-Code wird später erläutert.
Danach wird das Objekt für Transformationen festgelegt. ResourceResolver ist nur dafür verantwortlich, den Inhalt als Bytefolge abzurufen. Sie müssen kanonisieren, um den Digest aus den XML-Elementen zu erhalten. Transfomrs sind die Personen, die XML aus Bytes analysieren und kanonisieren.
Die erste Frage, die ich mir beim Signieren von XML gestellt habe, war, wie man es normalisiert. Wenn es nicht normalisiert wird, wird der Digest nicht korrekt ausgegeben. /www.w3.org/TR/xml-c14n11/), und transfomrs ist dafür verantwortlich.
Geben Sie diese Transformationen mit uri in addDocument an. Geben Sie null für Dateien an, die nicht konvertiert werden müssen.
sig.getSignedInfo().addResourceResolver(new MyResolver());
val transforms = new Transforms(kouseiBase);
transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
transforms.addTransform(Transforms.TRANSFORM_C14N_OMIT_COMMENTS);
sig.addDocument("#elem2", transforms, MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256);
sig.addDocument("somefile.txt", null, MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256);
Geben Sie anschließend das zu signierende Zertifikat und den privaten Schlüssel an. Die Signaturinformationen werden jetzt zum ersten Dokument hinzugefügt.
```java` sig.addKeyInfo(certificate); sig.addKeyInfo(certificate.getPublicKey()); sig.sign(privateKey);
4. ResourceResolverSpi
Verwenden Sie REsourceResolverSpi, um den URI aufzulösen. Es gibt zwei Methoden zur Implementierung: engineCanResolveURI und engineResolveURI. Ersteres prüft, ob der von addDocument angegebene URI von diesem Resolver aufgelöst werden kann. Letzteres ist eine Methode, um Inhalte von diesem Uri zu erhalten. Gibt ein Objekt namens XMLSignatureInput zurück.
Ich löse eine ResourceResolverException aus, wenn eine Ausnahme auftritt, weiß aber nicht, wie ich sie richtig machen soll. Der Codekonstruktor hier ist veraltet.
```java
class MyResolver extends ResourceResolverSpi {
@override
public XMLSignatureInput engineResolveURI(ResourceResolverContext context) throws ResourceResolverException {
val uri = context.attr.getValue();
try {
if (uri.equals("#elem2")) {
val result = new XMLSignatureInput(new ByteArrayInputStream("<elemt2>xxx</elem2>".getBytes("utf-8")));
result.setSourceURI(uri);
result.setMIMEType("text/xml");
return result;
}
if (uri.equals("somefile.txt")) {
val result = new XMLSignatureInput(new ByteArrayInputStream(new FileInputStream(uri)));
result.setSourceURI(uri);
result.setMIMEType("application/octet-stream");
return result;
}
} catch (Exception e) {
throw new ResourceResolverException("generic.EmptyMessage", e, uri, context.baseUri);
}
return null;
}
@override
public boolean engineCanResolveURI(ResourceResolverContext context) {
val uri = context.attr.getValue();
if (uri.equals("#elem2")) return true;
if (uri.equals("somefile.txt")) return true;
return false;
}
}
Sie können XML mit einem solchen Code signieren. Die XML-Signatur ist ziemlich verwirrend, aber die Bibliothek macht das Signieren relativ einfach. Es scheint jedoch, dass es nur wenige Dokumente gibt ...
Dewadewa