001package org.hl7.fhir.r4.utils;
002
003import java.io.ByteArrayInputStream;
004import java.io.FileOutputStream;
005import java.io.IOException;
006import java.io.OutputStream;
007import java.nio.file.Files;
008import java.nio.file.Paths;
009import java.security.InvalidAlgorithmParameterException;
010import java.security.KeyException;
011import java.security.KeyFactory;
012import java.security.KeyPair;
013import java.security.KeyPairGenerator;
014import java.security.NoSuchAlgorithmException;
015import java.security.PrivateKey;
016import java.security.PublicKey;
017import java.security.spec.PKCS8EncodedKeySpec;
018import java.security.spec.X509EncodedKeySpec;
019import java.util.Collections;
020
021import javax.xml.crypto.MarshalException;
022import javax.xml.crypto.dsig.CanonicalizationMethod;
023import javax.xml.crypto.dsig.DigestMethod;
024import javax.xml.crypto.dsig.Reference;
025import javax.xml.crypto.dsig.SignatureMethod;
026import javax.xml.crypto.dsig.SignedInfo;
027import javax.xml.crypto.dsig.Transform;
028import javax.xml.crypto.dsig.XMLSignature;
029import javax.xml.crypto.dsig.XMLSignatureException;
030import javax.xml.crypto.dsig.XMLSignatureFactory;
031import javax.xml.crypto.dsig.dom.DOMSignContext;
032import javax.xml.crypto.dsig.keyinfo.KeyInfo;
033import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
034import javax.xml.crypto.dsig.keyinfo.KeyValue;
035import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
036import javax.xml.crypto.dsig.spec.TransformParameterSpec;
037import javax.xml.parsers.DocumentBuilder;
038import javax.xml.parsers.DocumentBuilderFactory;
039import javax.xml.parsers.ParserConfigurationException;
040
041import org.hl7.fhir.exceptions.FHIRException;
042import org.hl7.fhir.utilities.xml.XmlGenerator;
043import org.w3c.dom.Document;
044import org.xml.sax.SAXException;
045
046public class DigitalSignatures {
047
048  public static PrivateKey getPrivateKey(String filename) throws Exception {
049
050    byte[] keyBytes = Files.readAllBytes(Paths.get(filename));
051
052    PKCS8EncodedKeySpec spec =
053        new PKCS8EncodedKeySpec(keyBytes);
054    KeyFactory kf = KeyFactory.getInstance("RSA");
055    return kf.generatePrivate(spec);
056  }
057
058  public static PublicKey getPublicKey(String filename) throws Exception {
059
060    byte[] keyBytes = Files.readAllBytes(Paths.get(filename));
061
062    X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
063    KeyFactory kf = KeyFactory.getInstance("RSA");
064    return kf.generatePublic(spec);
065  }
066
067  public static void main(String[] args) throws Exception {
068    // http://docs.oracle.com/javase/7/docs/technotes/guides/security/xmldsig/XMLDigitalSignature.html
069    //
070    byte[] inputXml = "<Envelope xmlns=\"urn:envelope\">\r\n</Envelope>\r\n".getBytes();
071    // load the document that's going to be signed
072    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
073    dbf.setNamespaceAware(true);
074    DocumentBuilder builder = dbf.newDocumentBuilder();  
075    Document doc = builder.parse(new ByteArrayInputStream(inputXml)); 
076    
077//    // create a key pair
078//    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
079//    kpg.initialize(512);
080//    KeyPair kp = kpg.generateKeyPair(); 
081    PublicKey pub = getPublicKey("C:\\work\\fhirserver\\tests\\signatures\\public_key.der");
082    PrivateKey priv = getPrivateKey("C:\\work\\fhirserver\\tests\\signatures\\private_key.der");
083    
084    // sign the document
085    DOMSignContext dsc = new DOMSignContext(priv, doc.getDocumentElement()); 
086    XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); 
087   
088    Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null), Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null, null);
089    SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref));
090    
091    KeyInfoFactory kif = fac.getKeyInfoFactory(); 
092    KeyValue kv = kif.newKeyValue(pub);
093    KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));
094    XMLSignature signature = fac.newXMLSignature(si, ki); 
095    signature.sign(dsc);
096    
097    OutputStream os = new FileOutputStream("c:\\temp\\java-digsig.xml");
098    new XmlGenerator().generate(doc.getDocumentElement(), os);
099  }
100}