import java.security.*;
import java.security.interfaces.*;
import java.io.*;

/** Tworzenie podpisu cyfrowego dla dokumentu XML */

public class SignXML
{
    public static void main(String[] args)
    {
        try
        {
            String keystorePassword = "changeit";
            String testAlias = "signkey";
            String testKeyPassword = "changeit";

// Tworzenie bazy keystore.
            KeyStore keystore = KeyStore.getInstance("JKS");

// Sprawdzenie lokalizacji bazy keystore użytkownika.
            String keystoreFilename = System.getProperty("user.home")+
                File.separator+".keystore";
                
// Wczytanie bazy keystore z odpowiedniego pliku.
            keystore.load(new FileInputStream(keystoreFilename),
                keystorePassword.toCharArray());

// Lokalizacja klucza ze wskazaną nazwą i hasłem.
            Key testkey = keystore.getKey(testAlias,
                testKeyPassword.toCharArray());

// Założenie, że dany klucz jest kluczem RSA.
            RSAPrivateKey pvtKey = (RSAPrivateKey) testkey;

// Pobranie certyfikatu dla tego klucza (nie na potrzeby wyliczenia podpisu,
// ale do zapisania w oddzielnym pliku do późniejszej weryfikacji podpisu).
            java.security.cert.Certificate cert =
                keystore.getCertificate(testAlias);

// Pobranie klucza publicznego z certyfikatu.
            RSAPublicKey pubKey = (RSAPublicKey) cert.getPublicKey();

// Tworzenie i inicjalizacja obiektu podpisu korzystającego z MD5 i RSA.
            Signature signer = Signature.getInstance("MD5withRSA");
            signer.initSign(pvtKey);

// Tworzenie skrótu wiadomości — podpis CML musi zawierać
// skrót wiadomości.
            MessageDigest digest = MessageDigest.getInstance("MD5");

// Otwieranie pliku XML.
            FileInputStream in = new FileInputStream(args[0]);

// Tworzenie bloku bajtowego do odczytu pliku.
            byte[] buffer = new byte[4096];
            int len;

// Odczyt bloku pliku i dołączenie go do obiektu podpisu.
            while ((len = in.read(buffer)) > 0)
            {
                signer.update(buffer, 0, len);
                digest.update(buffer, 0, len);
            }
            in.close();

// Wyliczenie podpisu cyfrowego.
            byte signatureBytes[] = signer.sign();

            byte digestBytes[] = digest.digest();
        
// Zapisanie podpisu do pliku.
            PrintWriter ps = new PrintWriter(
                new BufferedWriter(
                new FileWriter(args[0]+".sig.xml")));
            
            ps.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            ps.println("<Signature Id=\"SampleSignature\" xmlns=\"http://www.w3.org/2000/09/xmldsig#\">");
            ps.println("  <SignedInfo>");
            ps.println("    <CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-cl4n-20010315\"/>");
            ps.println("    <Reference URI=\"http://www.w3.org/TR/2000/REC-xhtml1-2000-126/\">");
            ps.println("      <Transforms>");
            ps.println("        <Transform Algorithm=\"http://www.w3.org/TR/2001/REC-xml-cl4n-20010315\"/>");
            ps.println("      </Transforms>");
            ps.println("      <DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#md5\"/>");
            ps.println("      <DigestValue>"+Base64.toBase64(digestBytes)+
                "</DigestValue>");
            ps.println("    </Reference>");
            ps.println("  </SignedInfo>");
            ps.println("  <SignatureValue>");
            ps.println("    "+Base64.toBase64(signatureBytes));
            ps.println("  </SignatureValue>");
            ps.println("  <KeyInfo>");
            ps.println("    <KeyValue>");
            ps.println("      <RSAKeyValue>");
            ps.println("        <Exponent>");
            ps.println("          "+Base64.toBase64(pubKey.getPublicExponent().toByteArray()));
            ps.println("        </Exponent>");
            ps.println("        <Modulus>");
            ps.println("          "+Base64.toBase64(pubKey.getModulus().
                toByteArray()));
            ps.println("        </Modulus>");
            ps.println("      </RSAKeyValue>");
            ps.println("    </KeyValue>");
            ps.println("  </KeyInfo>");
            ps.println("</Signature>");
            ps.close();
        }
        catch (Exception exc)
        {
            exc.printStackTrace();
        }
    }
}
