org.parelon.pskc.XmlManager.java Source code

Java tutorial

Introduction

Here is the source code for org.parelon.pskc.XmlManager.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.parelon.pskc;

import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.security.auth.DestroyFailedException;
import javax.swing.JOptionPane;
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.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.codec.DecoderException;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

/**
 * Class that handles all the operation of both parsing, editing and creating
 * the PKCS XML file.
 *
 * @author Vincenzo Abate
 */
public class XmlManager {

    private String fileName = "", folderOut = "", manufactuer = "", issuer = "", preSharedKeyName = "PARELON ONLUS";
    private String privateKeyFragment1 = "", privateKeyFragment2 = "", publicKey = "";
    private CryptManager crypto;

    public XmlManager(String manufactuer, String issuer) {
        this.manufactuer = manufactuer;
        this.issuer = issuer;
        this.crypto = new CryptManager();
    }

    private boolean validateSerial(String serialNo) {
        /**
         * validate the serial number: the serial must be formed by 9 integer
         * digits
         */
        try {
            if (serialNo.length() != 9) {
                return false;
            }
            return (Long.parseLong(serialNo) > 0);
        } catch (NumberFormatException ex) {
            return false;
        }
    }

    public void convertXml(String fileIn, String fileOut)
            throws FileNotFoundException, SAXException, IOException, InvalidKeyException, Base64DecodingException,
            NoSuchAlgorithmException, InvalidAlgorithmParameterException, IllegalBlockSizeException,
            BadPaddingException, NoSuchPaddingException, UnsupportedEncodingException, ParserConfigurationException,
            DecoderException, Exception {
        ArrayList<OtpSeed> seeds = new ArrayList<OtpSeed>();

        /**
         * Parserizzazione XML
         */
        FileInputStream fileToConvert = new FileInputStream(fileIn);
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document parsedXml = builder.parse(fileToConvert);
        fileToConvert.close();
        if (parsedXml.hasChildNodes()) {
            int validSerials = 0;
            NodeList keyPackages = parsedXml.getElementsByTagName("KeyPackage");
            for (int i = 0; i < keyPackages.getLength(); i++) {
                Node keyPackageNode = keyPackages.item(i);
                /**
                 * Parse PSKC node structure
                 */
                String serialNo = ((Element) keyPackageNode).getElementsByTagName("SerialNo").item(0)
                        .getTextContent();

                if (validateSerial(serialNo)) {
                    validSerials++;

                    OtpSeed validSeed = new OtpSeed();
                    validSeed.setSerialNo(serialNo);
                    validSeed.setCryptoId(String.format("KR-%06d", validSerials));
                    validSeed.setIssuer(issuer);
                    validSeed.setKeyId(String.format("%08d", validSerials));
                    validSeed.setManufacturer(manufactuer);

                    NodeList tempNode = ((Element) keyPackageNode).getElementsByTagName("xenc:CipherValue");
                    if (tempNode != null && tempNode.getLength() != 0) {
                        validSeed.setCipherValue(((Element) tempNode.item(0)).getTextContent());
                    }
                    seeds.add(validSeed);
                }
            }
        }

        /**
         * Creazione del nuovo XML
         */
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        // root elements
        Document doc = docBuilder.newDocument();
        doc.setXmlVersion("1.0");

        Element keyContainer = doc.createElement("KeyContainer");
        doc.appendChild(keyContainer);
        keyContainer.setAttribute("xmlns", "urn:ietf:params:xml:ns:keyprov:pskc");
        keyContainer.setAttribute("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#");
        keyContainer.setAttribute("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#");
        keyContainer.setAttribute("Version", "1.0");
        keyContainer.setAttribute("ID", "KC0001");

        /**
         * Key Name
         */
        Element encryptionKey = doc.createElement("EncryptionKey");
        keyContainer.appendChild(encryptionKey);
        Element ds_keyName = doc.createElement("ds:KeyName");
        encryptionKey.appendChild(ds_keyName);
        ds_keyName.setTextContent(this.preSharedKeyName);

        /**
         * MAC Method
         */
        Element macMethod = doc.createElement("MACMethod");
        keyContainer.appendChild(macMethod);
        macMethod.setAttribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#hmac-sha1");
        /**
         * Mac Key
         */
        Element macKey = doc.createElement("MACKey");
        macMethod.appendChild(macKey);
        /**
         * EncryptionMethod
         */
        Element encryptionMethod = doc.createElement("xenc:EncryptionMethod");
        macKey.appendChild(encryptionMethod);
        encryptionMethod.setAttribute("Algorithm", "http://www.w3.org/2001/04/xmlenc#aes128-cbc");
        /**
         * xenc:CipherData
         */
        Element xenc_CipherData = doc.createElement("xenc:CipherData");
        macKey.appendChild(xenc_CipherData);
        /**
         * xenc:CipherValue
         */
        Element xenc_CipherValue = doc.createElement("xenc:CipherValue");
        xenc_CipherData.appendChild(xenc_CipherValue);

        /**
         * Passo 1: Criptare la MAC Key
         */
        String macSignature = Base64.encode(crypto.getAesCipheredMacKey());
        xenc_CipherValue.setTextContent(macSignature);

        for (OtpSeed seed : seeds) {
            /**
             * Passo 2: Convertire il dato criptato
             */
            byte[] reCipheredSecretBytes = crypto.convertRsaToAes(seed.getCipherValue());
            seed.setCipherValue(Base64.encode(reCipheredSecretBytes));
            /**
             * Passo 3: Firmare il dato criptato
             */
            byte[] secretSignatureBytes = crypto.signCipheredSecret(reCipheredSecretBytes);
            seed.setValueMac(Base64.encode(secretSignatureBytes));

            /**
             * KeyPackage
             */
            Element keyPackageElement = doc.createElement("KeyPackage");
            keyContainer.appendChild(keyPackageElement);
            /**
             * DeviceInfo
             */
            Element deviceInfoElement = doc.createElement("DeviceInfo");
            keyPackageElement.appendChild(deviceInfoElement);
            /**
             * Manufactuer
             */
            Element manufactuerElement = doc.createElement("Manufactuer");
            manufactuerElement.setTextContent(seed.getManufacturer());
            deviceInfoElement.appendChild(manufactuerElement);
            /**
             * SerialNo
             */
            Element serialNoElement = doc.createElement("SerialNo");
            serialNoElement.setTextContent(seed.getSerialNo());
            deviceInfoElement.appendChild(serialNoElement);
            /**
             * CryptoModuleInfo
             */
            Element cryptoModuleInfoElement = doc.createElement("CryptoModuleInfo");
            keyPackageElement.appendChild(cryptoModuleInfoElement);
            /**
             * ID
             */
            Element idElement = doc.createElement("ID");
            idElement.setTextContent(seed.getCryptoId());
            cryptoModuleInfoElement.appendChild(idElement);
            /**
             * Key
             */
            Element keyElement = doc.createElement("Key");
            keyPackageElement.appendChild(keyElement);
            keyElement.setAttribute("Id", seed.getKeyId());
            if (seed.getType().equals("TOTP")) {
                keyElement.setAttribute("Algorithm", "urn:ietf:params:xml:ns:keyprov:pskc:totp");
            } else if (seed.getType().equals("HOTP")) {
                keyElement.setAttribute("Algorithm", "urn:ietf:params:xml:ns:keyprov:pskc:hotp");
            } else {
                throw new Exception("OTP type not supported");
            }

            /**
             * Issuer
             */
            Element issuerElement = doc.createElement("Issuer");
            issuerElement.setTextContent(seed.getIssuer());
            keyElement.appendChild(issuerElement);
            /**
             * AlgorithmParameters
             */
            Element algorithmParametersElement = doc.createElement("AlgorithmParameters");
            keyElement.appendChild(algorithmParametersElement);
            /**
             * ResponseFormat
             */
            Element responseFormatElement = doc.createElement("ResponseFormat");
            algorithmParametersElement.appendChild(responseFormatElement);
            responseFormatElement.setAttribute("Length", seed.getLength());
            responseFormatElement.setAttribute("Encoding", seed.getEncoding());
            /**
             * Data
             */
            Element dataElement = doc.createElement("Data");
            keyElement.appendChild(dataElement);
            /**
             * Secret
             */
            Element secretElement = doc.createElement("Secret");
            dataElement.appendChild(secretElement);
            /**
             * EncryptedValue
             */
            Element encryptedValueElement = doc.createElement("EncryptedValue");
            secretElement.appendChild(encryptedValueElement);
            /**
             * xenc:EncryptionMethod
             */
            Element encryptionMethodElement = doc.createElement("xenc:EncryptionMethod");
            encryptedValueElement.appendChild(encryptionMethodElement);
            encryptionMethodElement.setAttribute("Algorithm", "http://www.w3.org/2001/04/xmlenc#aes128-cbc");
            /**
             * xenc:CipherData
             */
            Element cipherDataElement = doc.createElement("xenc:CipherData");
            encryptedValueElement.appendChild(cipherDataElement);
            /**
             * xenc:CipherValue
             */
            Element cipherValueElement = doc.createElement("xenc:CipherValue");
            cipherValueElement.setTextContent(seed.getCipherValue());
            cipherDataElement.appendChild(cipherValueElement);
            /**
             * ValueMAC
             */
            Element valueMACElement = doc.createElement("ValueMAC");
            valueMACElement.setTextContent(seed.getValueMac());
            secretElement.appendChild(valueMACElement);
            /**
             * Counter
             */
            Element counterElement = doc.createElement("Counter");
            dataElement.appendChild(counterElement);
            /**
             * PlainValue
             */
            Element counterPlainValueElement = doc.createElement("PlainValue");
            counterPlainValueElement.setTextContent(seed.getCounter());
            counterElement.appendChild(counterPlainValueElement);
            /**
             * TimeInterval
             */
            Element timeIntervalElement = doc.createElement("TimeInterval");
            dataElement.appendChild(timeIntervalElement);
            /**
             * PlainValue
             */
            Element timeIntervalPlainValueElement = doc.createElement("PlainValue");
            timeIntervalPlainValueElement.setTextContent(seed.getTimeInterval());
            timeIntervalElement.appendChild(timeIntervalPlainValueElement);
            /**
             * Time
             */
            Element timeElement = doc.createElement("Time");
            dataElement.appendChild(timeElement);
            /**
             * PlainValue
             */
            Element timePlainValueElement = doc.createElement("PlainValue");
            timePlainValueElement.setTextContent(seed.getTime());
            timeElement.appendChild(timePlainValueElement);
        }

        doc.normalizeDocument();
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
        DOMSource source = new DOMSource(doc);

        StreamResult result = new StreamResult(new File(fileOut));
        transformer.transform(source, result);
    }

    public String initializeCrypto(byte[] fragment1, byte[] fragment2, byte[] publicKey)
            throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException,
            Base64DecodingException, UnsupportedEncodingException, DestroyFailedException, DecoderException {
        return crypto.initAll(fragment1, fragment2, publicKey);
    }

    public String initializeCrypto(byte[] fragment1, byte[] fragment2)
            throws NoSuchAlgorithmException, InvalidKeySpecException, Base64DecodingException,
            NoSuchPaddingException, InvalidKeyException, DecoderException {
        crypto.initRsaOperations(fragment1, fragment2);
        crypto.initHmacOperations();
        return crypto.initAesOperations();
    }
}