/* * EncFS Java Library * Copyright (C) 2011 Mark R. Pariente * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. */ package org.mrpdaemon.sec.encfs; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * Parser methods that read and interpret EncFS configuration files. */ public final class EncFSConfigParser { private EncFSConfigParser() { } private static String getNodeValue(Node n) { return n.getChildNodes().item(0).getNodeValue(); } /** * Parse the given configuration file * * @param configFile * EncFS volume configuration file. * @return An EncFSConfig object containing the configuration data * interpreted from the given file. */ public static EncFSConfig parseFile(File configFile) throws ParserConfigurationException, SAXException, IOException, EncFSInvalidConfigException, EncFSUnsupportedException { FileInputStream inputStream = new FileInputStream(configFile); try { return parseFile(inputStream); } finally { inputStream.close(); } } /** * Parse the configuration file residing on an EncFSFileProvider with the * given path * * @param fileProvider * File provider to access the config file * @param path * Path of the config file in the file provider's notation * @return An EncFSConfig object representing the parsing result */ public static EncFSConfig parseConfig(EncFSFileProvider fileProvider, String path) throws EncFSUnsupportedException, EncFSInvalidConfigException, IOException { if (!fileProvider.exists(fileProvider.getFilesystemRootPath()+path)) { // Try old versions for (String altConfigFileName : EncFSVolume.OLD_CONFIG_FILE_NAMES) { if (fileProvider.exists(fileProvider.getFilesystemRootPath()+altConfigFileName)) { throw new EncFSUnsupportedException("Unsupported EncFS version"); } } throw new EncFSInvalidConfigException("No EncFS configuration file found"); } EncFSConfig config; // Parse the configuration file try { config = EncFSConfigParser.parseFile(fileProvider .openInputStream(fileProvider.getFilesystemRootPath() +path)); } catch (ParserConfigurationException e2) { throw new EncFSUnsupportedException("XML parser not supported"); } catch (SAXException e2) { throw new EncFSInvalidConfigException("Parse error in config file"); } catch (IOException e2) { throw new EncFSInvalidConfigException("Couldn't open config file"); } // Validate the configuration config.validate(); return config; } /** * Parse the given configuration file from a stream * * @param inputStream * InputStream for the config file * @return An EncFSConfig object containing the configuration data * interpreted from the given file. */ private static EncFSConfig parseFile(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException, EncFSInvalidConfigException { DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(inputStream); doc.getDocumentElement().normalize(); NodeList cfgNodeList = doc.getElementsByTagName("cfg").item(0).getChildNodes(); if (cfgNodeList.getLength()==0) { throw new EncFSInvalidConfigException("<cfg> element not present in config file"); } EncFSConfig config = EncFSConfigFactory.createDefault(); for (int i = 0; i<cfgNodeList.getLength(); i++) { Node cfgNode = cfgNodeList.item(i); if (cfgNode.getNodeType()==Node.ELEMENT_NODE) { if (cfgNode.getNodeName().equals("nameAlg")) { NodeList nameAlgNodeList = cfgNode.getChildNodes(); for (int j = 0; j<nameAlgNodeList.getLength(); j++) { Node nameAlgChildNode = nameAlgNodeList.item(j); if (nameAlgChildNode.getNodeName().equals("name")) { String algName = getNodeValue(nameAlgChildNode); try { config.setFilenameAlgorithm(EncFSFilenameEncryptionAlgorithm.parse(algName)); } catch (IllegalArgumentException e) { throw new EncFSInvalidConfigException("Unknown name algorithm in config file: "+algName); } } } } else if (cfgNode.getNodeName().equals("keySize")) { config.setVolumeKeySizeInBits(Integer.parseInt(getNodeValue(cfgNode))); } else if (cfgNode.getNodeName().equals("blockSize")) { config.setEncryptedFileBlockSizeInBytes(Integer.parseInt(getNodeValue(cfgNode))); } else if (cfgNode.getNodeName().equals("uniqueIV")) { config.setUseUniqueIV(Integer.parseInt(getNodeValue(cfgNode))==1); } else if (cfgNode.getNodeName().equals("chainedNameIV")) { config.setChainedNameIV(Integer.parseInt(getNodeValue(cfgNode))==1); } else if (cfgNode.getNodeName().equals("allowHoles")) { config.setHolesAllowedInFiles(Integer.parseInt(getNodeValue(cfgNode))==1); } else if (cfgNode.getNodeName().equals("encodedKeySize")) { config.setEncodedKeyLengthInBytes(Integer.parseInt(getNodeValue(cfgNode))); } else if (cfgNode.getNodeName().equals("encodedKeyData")) { config.setBase64EncodedVolumeKey(getNodeValue(cfgNode)); } else if (cfgNode.getNodeName().equals("saltLen")) { config.setSaltLengthBytes(Integer.parseInt(getNodeValue(cfgNode))); } else if (cfgNode.getNodeName().equals("saltData")) { config.setBase64Salt(getNodeValue(cfgNode)); } else if (cfgNode.getNodeName().equals("kdfIterations")) { config.setIterationForPasswordKeyDerivationCount(Integer.parseInt(getNodeValue(cfgNode))); } else if (cfgNode.getNodeName().equals("blockMACBytes")) { config.setNumberOfMACBytesForEachFileBlock(Integer.parseInt(getNodeValue(cfgNode))); } else if (cfgNode.getNodeName().equals("blockMACRandBytes")) { config.setNumberOfRandomBytesInEachMACHeader(Integer.parseInt(getNodeValue(cfgNode))); } else if (cfgNode.getNodeName().equals("externalIVChaining")) { config.setSupportedExternalIVChaining(Integer.parseInt(getNodeValue(cfgNode))==1); } } } return config; } }