├── .gitignore ├── AUTHORS ├── LICENSE ├── README.md ├── pom.xml ├── src ├── main │ ├── java │ │ ├── EncFSShell.java │ │ └── org │ │ │ └── mrpdaemon │ │ │ └── sec │ │ │ └── encfs │ │ │ ├── BasicFilenameDecryptionStrategy.java │ │ │ ├── BasicFilenameEncryptionStrategy.java │ │ │ ├── BlockCrypto.java │ │ │ ├── BlockFilenameDecryptionStrategy.java │ │ │ ├── BlockFilenameEncryptionStrategy.java │ │ │ ├── EncFSBase64.java │ │ │ ├── EncFSChecksumException.java │ │ │ ├── EncFSConfig.java │ │ │ ├── EncFSConfigFactory.java │ │ │ ├── EncFSConfigParser.java │ │ │ ├── EncFSConfigWriter.java │ │ │ ├── EncFSCorruptDataException.java │ │ │ ├── EncFSCrypto.java │ │ │ ├── EncFSException.java │ │ │ ├── EncFSFile.java │ │ │ ├── EncFSFileInfo.java │ │ │ ├── EncFSFileInputStream.java │ │ │ ├── EncFSFileOutputStream.java │ │ │ ├── EncFSFileProvider.java │ │ │ ├── EncFSFilenameEncryptionAlgorithm.java │ │ │ ├── EncFSInputStream.java │ │ │ ├── EncFSInvalidConfigException.java │ │ │ ├── EncFSInvalidPasswordException.java │ │ │ ├── EncFSLocalFileProvider.java │ │ │ ├── EncFSOutputStream.java │ │ │ ├── EncFSPBKDF2Provider.java │ │ │ ├── EncFSProgressListener.java │ │ │ ├── EncFSUnsupportedException.java │ │ │ ├── EncFSUtil.java │ │ │ ├── EncFSVolume.java │ │ │ ├── EncFSVolumeBuilder.java │ │ │ ├── FilenameDecryptionStrategy.java │ │ │ ├── FilenameEncryptionStrategy.java │ │ │ ├── NullFilenameDecryptionStrategy.java │ │ │ ├── NullFilenameEncryptionStrategy.java │ │ │ ├── StreamCrypto.java │ │ │ ├── StreamFilenameDecryptionStrategy.java │ │ │ ├── StreamFilenameEncryptionStrategy.java │ │ │ └── VolumeKey.java │ └── resources │ │ └── org │ │ └── mrpdaemon │ │ └── sec │ │ └── encfs │ │ └── library.properties └── test │ └── java │ └── org │ └── mrpdaemon │ └── sec │ └── encfs │ └── tests │ ├── EncFSBase64Test.java │ ├── EncFSComparer.java │ ├── EncFSCryptoTest.java │ ├── EncFSFilenameEncryptionAlgorithmTest.java │ ├── EncFSUtilTest.java │ ├── EncFSVolumeFileTest.java │ ├── EncFSVolumeIntegrationTest.java │ ├── EncFSVolumeTest.java │ ├── EncFSVolumeTestCommon.java │ ├── EncFSVolumeVFSTest.java │ └── vfs │ ├── CommonsVFSFileProvider.java │ └── CommonsVFSRamFileProvider.java └── test └── encfs_samples ├── Samples.txt ├── boxcryptor_1 ├── .encfs6.xml └── W3gLoUqL-0YzUh8udP8 ├── boxcryptor_2 ├── .encfs6.xml ├── Z4Qzgr-iwj-1dgA └── hc2yatLg │ └── lcgwUaXICbCjBW4 ├── boxcryptor_3 ├── .encfs6.xml ├── cJTbxx2GhjzRDYYra4twBcIr0-pPGtD └── desktop.ini ├── boxcryptor_null ├── .encfs6.xml └── testfile.txt ├── testvol-blockmac ├── .encfs6.xml └── 85hMcPOogQFKISDxPi,QcvlY ├── testvol-default ├── .encfs6.xml ├── kNmBCW-Coq1CvGZ1EabjsiB4 ├── ko1GW2gcuNSbGWQryepRJpSC └── qQQTyqU5n10lZYe-YTOfkTo2 ├── testvol-extivchn ├── .encfs6.xml ├── CjIsKUMxWNJZJ5mLWPboFUb5 │ └── FGSPI4b,efiE-vCHTF5-XAmw7jeS35Jy,EgYsJ7nhxwRN- └── pWxw6SiMcDvaieR0K9IS4f0n ├── testvol-nouniqueiv ├── .encfs6.xml ├── XSuCblFoZx5WZQFkf3O6E8HS └── fFHqdbodgs8p5Q1NH,pjhHle └── testvol-streamname ├── .encfs6.xml └── 7W2,dU4 └── H-mMw-IyZnf6SdpOZo, /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | .settings 4 | eclipse_bin 5 | target 6 | .idea 7 | *.iml 8 | .vimrc 9 | cscope* 10 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Authors: 2 | Mark Pariente 3 | Andrew Ormerod 4 | Lars Gohlke 5 | 6 | Contributors: 7 | michael1 (GitHub) 8 | Zdenek Farana 9 | Joscha Feth -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | encfs-java 2 | ========== 3 | 4 | encfs-java is a Java library for accessing data in 5 | [EncFS](http://www.arg0.net/encfs) volumes. It is able to derive the volume key 6 | from a user password, decode encrypted filenames (IV chaining is implemented), 7 | decrypt file contents, create new volumes, move/copy/rename files and 8 | directories within the volume as well as encrypt file contents into the 9 | volume 10 | 11 | We do support all encfs volume configuration options, and are interoperable 12 | with the official encfs implementation (http://www.arg0.net/encfs). Currently 13 | we only support volume created with the latest version (1.7.4), but we target 14 | to be able to support volumes created with legacy versions as well. 15 | 16 | ## Building 17 | 18 | encfs-java uses [Maven](http://maven.apache.org) for building. Assuming you 19 | have a working installation, simply run the following to build the code: 20 | 21 | $ mvn compile 22 | 23 | To create a JAR file for using encfs-java from another application, do: 24 | 25 | $ mvn package 26 | 27 | Which will create a JAR file in the {$PROJECT_ROOT}/target/ directory. 28 | 29 | ## Usage 30 | 31 | This library comes with a demo/example application called EncFSShell. It is a 32 | simple shell supporting a few commands such as 'ls', 'cd', 'cat', 'mv' and 'cp' 33 | on an EncFS volume. After building the library, add the 34 | {$PROJECT_ROOT}/target/classes/ directory to your CLASSPATH, and run like so: 35 | 36 | $ java -classpath ${PROJECT_ROOT}/target/classes EncFSShell /path/to/an/encfs/volume 37 | 38 | For using the library from another project, include the .JAR file in your 39 | classpath and import the org.mrpdaemon.encfs.sec package.s 40 | 41 | ## API Documentation 42 | 43 | For API documentation, see: 44 | 45 | http://mrpdaemon.github.com/encfs-java/apidocs/index.html 46 | 47 | To test your own comment changes, generate up-to-date docs using Maven: 48 | 49 | $ mvn javadoc:javadoc 50 | 51 | Which will place your documentation in ${PROJECT_ROOT}/target/site/apidocs/ 52 | 53 | ## Common issues 54 | 55 | If you are getting an exception due to "Illegal key size" and you are using Sun's JDK, 56 | you need to install the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction 57 | Policy Files. See the following link for more information: 58 | 59 | Java 6 JCE Link http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html 60 | Java 7 JCE Link http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html 61 | Java 8 JCE Link http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html 62 | Extract files into JDK/JRE/lib/security folder (To whichever version of JRE/JDK x64/x86 you are using) 63 | 64 | Thanks to aormerod for pointing this out! 65 | 66 | ## Licensing 67 | 68 | encfs-java is licensed under the Lesser GNU Public License, which allows non-GPL 69 | applications to make use of the library with the restriction that the source code 70 | for any modifications to the library itself need to be made available to be able 71 | to legally redistribute the modified library. For more information, please see the 72 | LICENSE file and the Free Software Foundation 73 | [website](http://www.gnu.org/licenses/lgpl.html). 74 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | org.mrpdaemon.sec.encfs 5 | encfs-java 6 | jar 7 | 0.9-dev 8 | encfs-java 9 | http://maven.apache.org 10 | 11 | UTF-8 12 | 13 | 14 | 15 | 16 | junit 17 | junit 18 | 4.10 19 | test 20 | 21 | 22 | org.slf4j 23 | slf4j-api 24 | 1.6.4 25 | 26 | 27 | org.slf4j 28 | slf4j-simple 29 | 1.6.4 30 | test 31 | 32 | 33 | org.apache.commons 34 | commons-vfs2 35 | 2.0 36 | test 37 | 38 | 39 | 40 | 41 | 42 | org.apache.maven.plugins 43 | maven-jar-plugin 44 | 2.4 45 | 46 | 47 | 48 | EncFSShell 49 | 50 | 51 | 52 | 53 | 54 | maven-compiler-plugin 55 | 3.0 56 | 57 | UTF-8 58 | 1.6 59 | 1.6 60 | 61 | 62 | 63 | maven-surefire-plugin 64 | 2.12.4 65 | 66 | methods 67 | 68 | 69 | 70 | 71 | 72 | 73 | src/main/resources 74 | true 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/BasicFilenameDecryptionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | import java.util.Arrays; 18 | 19 | // Common class for filename decryption strategies 20 | abstract class BasicFilenameDecryptionStrategy extends 21 | FilenameDecryptionStrategy { 22 | 23 | BasicFilenameDecryptionStrategy(EncFSVolume volume, String volumePath, 24 | EncFSFilenameEncryptionAlgorithm algorithm) { 25 | super(volume, volumePath, algorithm); 26 | } 27 | 28 | // Actual decryption to be implemented by the subclass 29 | protected abstract byte[] decryptConcrete(EncFSVolume volume, 30 | byte[] encFileName, byte[] fileIv) throws EncFSCorruptDataException; 31 | 32 | // Filename decryption implementation 33 | protected String decryptImpl(String fileName) 34 | throws EncFSCorruptDataException, EncFSChecksumException { 35 | EncFSVolume volume = getVolume(); 36 | String volumePath = getVolumePath(); 37 | EncFSConfig config = volume.getConfig(); 38 | 39 | byte[] chainIv = EncFSCrypto.computeChainedIV(volume, volumePath, 40 | config); 41 | byte[] base256FileName = EncFSBase64.decodeEncfs(fileName.getBytes()); 42 | byte[] macBytes; 43 | 44 | try { 45 | macBytes = EncFSCrypto.getMacBytes(base256FileName); 46 | } catch (ArrayIndexOutOfBoundsException e) { 47 | /* 48 | * It's possible for fileName to be malformed so as to make 49 | * base256FileName shorter than 2 bytes. In this case, getMacBytes() 50 | * will throw an exception. 51 | */ 52 | throw new EncFSCorruptDataException(e); 53 | } 54 | 55 | byte[] encFileName = Arrays.copyOfRange(base256FileName, 2, 56 | base256FileName.length); 57 | 58 | if (encFileName.length == 0) { 59 | throw new EncFSCorruptDataException( 60 | "Malformed file name (too short)"); 61 | } 62 | 63 | byte[] fileIv = EncFSCrypto.computeFileIV(chainIv, macBytes); 64 | 65 | byte[] decFileName = decryptConcrete(volume, encFileName, fileIv); 66 | 67 | verifyDecryptionWorked(volume, chainIv, base256FileName, decFileName); 68 | 69 | return decryptPost(decFileName); 70 | } 71 | 72 | // Post decrpytion hook for subclasses 73 | protected abstract String decryptPost(byte[] fileName); 74 | 75 | // Verify that the decryption worked 76 | private void verifyDecryptionWorked(EncFSVolume volume, byte[] chainIv, 77 | byte[] base256FileName, byte[] decFileName) 78 | throws EncFSChecksumException { 79 | // Verify decryption worked 80 | // current versions store the checksum at the beginning (encfs 0.x 81 | // stored checksums at the end) 82 | byte[] mac16; 83 | if (volume.getConfig().isChainedNameIV()) { 84 | mac16 = EncFSCrypto.mac16(volume.getMAC(), decFileName, chainIv); 85 | } else { 86 | mac16 = EncFSCrypto.mac16(volume.getMAC(), decFileName); 87 | } 88 | 89 | byte[] expectedMac = Arrays.copyOfRange(base256FileName, 0, 2); 90 | if (!Arrays.equals(mac16, expectedMac)) { 91 | throw new EncFSChecksumException("Mismatch in file name checksum"); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/BasicFilenameEncryptionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | import java.util.Arrays; 18 | 19 | // Common class for filename encryption strategies 20 | abstract class BasicFilenameEncryptionStrategy extends 21 | FilenameEncryptionStrategy { 22 | 23 | BasicFilenameEncryptionStrategy(EncFSVolume volume, String volumePath, 24 | EncFSFilenameEncryptionAlgorithm algorithm) { 25 | super(volume, volumePath, algorithm); 26 | } 27 | 28 | // Actual encryption to be implemented by the subclass 29 | protected abstract byte[] encryptConcrete(EncFSVolume volume, 30 | byte[] paddedDecFileName, byte[] fileIv) 31 | throws EncFSCorruptDataException; 32 | 33 | // Filename encryption implementation 34 | protected String encryptImpl(String fileName) 35 | throws EncFSCorruptDataException { 36 | EncFSVolume volume = getVolume(); 37 | String volumePath = getVolumePath(); 38 | EncFSConfig config = volume.getConfig(); 39 | 40 | byte[] decFileName = fileName.getBytes(); 41 | byte[] paddedDecFileName = getPaddedDecFilename(decFileName); 42 | byte[] chainIv = EncFSCrypto.computeChainedIV(volume, volumePath, 43 | config); 44 | byte[] mac16 = getMac16(volume, paddedDecFileName, chainIv); 45 | byte[] macBytes = EncFSCrypto.getMacBytes(mac16); 46 | byte[] fileIv = EncFSCrypto.computeFileIV(chainIv, macBytes); 47 | 48 | byte[] encFileName = encryptConcrete(volume, paddedDecFileName, fileIv); 49 | 50 | return getBase256Filename(mac16, encFileName); 51 | } 52 | 53 | // Filename padding implementation hook for subclasses 54 | protected abstract byte[] getPaddedDecFilename(byte[] decFileName); 55 | 56 | // Returns the base 256 filename for the given encrypted filename 57 | private String getBase256Filename(byte[] mac16, byte[] encFileName) { 58 | // current versions store the checksum at the beginning (encfs 0.x 59 | // stored checksums at the end) 60 | 61 | byte[] base256FileName = new byte[encFileName.length + 2]; 62 | base256FileName[0] = mac16[0]; 63 | base256FileName[1] = mac16[1]; 64 | System.arraycopy(encFileName, 0, base256FileName, 2, encFileName.length); 65 | 66 | byte[] fileNameOutput = EncFSBase64.encodeEncfs(base256FileName); 67 | 68 | return new String(fileNameOutput); 69 | } 70 | 71 | // Returns the mac16 of the given file name 72 | private byte[] getMac16(EncFSVolume volume, byte[] paddedDecFileName, 73 | byte[] chainIv) { 74 | if (volume.getConfig().isChainedNameIV()) { 75 | return EncFSCrypto.mac16(volume.getMAC(), paddedDecFileName, 76 | Arrays.copyOf(chainIv, chainIv.length)); 77 | } else { 78 | return EncFSCrypto.mac16(volume.getMAC(), paddedDecFileName); 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/BlockCrypto.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | import javax.crypto.BadPaddingException; 18 | import javax.crypto.Cipher; 19 | import javax.crypto.IllegalBlockSizeException; 20 | import java.security.InvalidAlgorithmParameterException; 21 | 22 | // Static methods for block cryptography 23 | class BlockCrypto { 24 | 25 | // Returns a new block cipher object 26 | protected static Cipher newBlockCipher() throws EncFSUnsupportedException { 27 | return EncFSCrypto.getCipher(EncFSCrypto.BLOCK_CIPHER); 28 | } 29 | 30 | // Common method to perform a block operation 31 | private static byte[] blockOperation(EncFSVolume volume, byte[] ivSeed, 32 | byte[] data, int opMode) throws InvalidAlgorithmParameterException, 33 | IllegalBlockSizeException, BadPaddingException { 34 | Cipher cipher = volume.getBlockCipher(); 35 | EncFSCrypto.cipherInit(volume, opMode, cipher, ivSeed); 36 | return cipher.doFinal(data); 37 | } 38 | 39 | // Perform block encryption 40 | protected static byte[] blockDecrypt(EncFSVolume volume, byte[] ivSeed, 41 | byte[] data) throws InvalidAlgorithmParameterException, 42 | IllegalBlockSizeException, BadPaddingException { 43 | return blockOperation(volume, ivSeed, data, Cipher.DECRYPT_MODE); 44 | } 45 | 46 | // Perform block decryption 47 | protected static byte[] blockEncrypt(EncFSVolume volume, byte[] ivSeed, 48 | byte[] data) throws IllegalBlockSizeException, 49 | InvalidAlgorithmParameterException, BadPaddingException { 50 | return blockOperation(volume, ivSeed, data, Cipher.ENCRYPT_MODE); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/BlockFilenameDecryptionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | import javax.crypto.BadPaddingException; 18 | import javax.crypto.IllegalBlockSizeException; 19 | import java.security.InvalidAlgorithmParameterException; 20 | import java.util.Arrays; 21 | 22 | // Implementation of block filename decryption strategy 23 | class BlockFilenameDecryptionStrategy extends BasicFilenameDecryptionStrategy { 24 | 25 | BlockFilenameDecryptionStrategy(EncFSVolume volume, String volumePath) { 26 | super(volume, volumePath, EncFSFilenameEncryptionAlgorithm.BLOCK); 27 | } 28 | 29 | // Block decryption 30 | protected byte[] decryptConcrete(EncFSVolume volume, byte[] encFileName, 31 | byte[] fileIv) throws EncFSCorruptDataException { 32 | try { 33 | return BlockCrypto.blockDecrypt(volume, fileIv, encFileName); 34 | } catch (InvalidAlgorithmParameterException e) { 35 | throw new EncFSCorruptDataException(e); 36 | } catch (IllegalBlockSizeException e) { 37 | throw new EncFSCorruptDataException(e); 38 | } catch (BadPaddingException e) { 39 | throw new EncFSCorruptDataException(e); 40 | } 41 | } 42 | 43 | // Remove padding after decryption 44 | protected String decryptPost(byte[] fileName) { 45 | int padLen = fileName[fileName.length - 1]; 46 | 47 | return new String(Arrays.copyOfRange(fileName, 0, fileName.length 48 | - padLen)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/BlockFilenameEncryptionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | import javax.crypto.BadPaddingException; 18 | import javax.crypto.IllegalBlockSizeException; 19 | import java.security.InvalidAlgorithmParameterException; 20 | import java.util.Arrays; 21 | 22 | // Implementation of block filename encryption strategy 23 | class BlockFilenameEncryptionStrategy extends BasicFilenameEncryptionStrategy { 24 | 25 | BlockFilenameEncryptionStrategy(EncFSVolume volume, String volumePath) { 26 | super(volume, volumePath, EncFSFilenameEncryptionAlgorithm.BLOCK); 27 | } 28 | 29 | // Block encryption 30 | @Override 31 | protected byte[] encryptConcrete(EncFSVolume volume, 32 | byte[] paddedDecFileName, byte[] fileIv) 33 | throws EncFSCorruptDataException { 34 | try { 35 | return BlockCrypto.blockEncrypt(volume, fileIv, paddedDecFileName); 36 | } catch (InvalidAlgorithmParameterException e) { 37 | throw new EncFSCorruptDataException(e); 38 | } catch (IllegalBlockSizeException e) { 39 | throw new EncFSCorruptDataException(e); 40 | } catch (BadPaddingException e) { 41 | throw new EncFSCorruptDataException(e); 42 | } 43 | } 44 | 45 | // Padding implementation 46 | protected byte[] getPaddedDecFilename(byte[] decFileName) { 47 | // Pad to the nearest 16 bytes, add a full block if needed 48 | int padBytesSize = 16; 49 | int padLen = padBytesSize - (decFileName.length % padBytesSize); 50 | if (padLen == 0) { 51 | padLen = padBytesSize; 52 | } 53 | byte[] paddedDecFileName = Arrays.copyOf(decFileName, 54 | decFileName.length + padLen); 55 | Arrays.fill(paddedDecFileName, decFileName.length, 56 | paddedDecFileName.length, (byte) padLen); 57 | return paddedDecFileName; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSChecksumException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | public class EncFSChecksumException extends EncFSException { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | public EncFSChecksumException(String message) { 23 | super(message); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | /** 19 | * Class representing an EncFS volume configuration. 20 | * 21 | */ 22 | public class EncFSConfig { 23 | 24 | private int volumeKeySizeInBits; 25 | private int encryptedFileBlockSizeInBytes; 26 | private boolean useUniqueIV; 27 | 28 | /* 29 | * Whether name IV chaining is being used. When using IV chaining, each 30 | * parent element in a file's path contributes to the IV that is used to 31 | * encrypt the file's name. 32 | */ 33 | private boolean chainedNameIV; 34 | private boolean holesAllowedInFiles; 35 | private int encodedKeyLengthInBytes; 36 | 37 | /* 38 | * String containing the Base64 encoded representation of the volume 39 | * encryption key encrypted with the password generated key. 40 | */ 41 | private String base64EncodedVolumeKey; 42 | private int saltLengthBytes; 43 | 44 | /* 45 | * String containing the salt data applied to the password hash for 46 | * generating the password derived key. 47 | */ 48 | private String base64Salt; 49 | private int iterationForPasswordKeyDerivationCount; 50 | private EncFSFilenameEncryptionAlgorithm filenameAlgorithm; 51 | private int numberOfMACBytesForEachFileBlock; 52 | private int numberOfRandomBytesInEachMACHeader; 53 | private boolean supportedExternalIVChaining; 54 | 55 | public EncFSConfig() { 56 | } 57 | 58 | public int getVolumeKeySizeInBits() { 59 | return volumeKeySizeInBits; 60 | } 61 | 62 | public void setVolumeKeySizeInBits(int volumeKeySizeInBits) { 63 | this.volumeKeySizeInBits = volumeKeySizeInBits; 64 | } 65 | 66 | public int getEncryptedFileBlockSizeInBytes() { 67 | return encryptedFileBlockSizeInBytes; 68 | } 69 | 70 | public void setEncryptedFileBlockSizeInBytes( 71 | int encryptedFileBlockSizeInBytes) { 72 | this.encryptedFileBlockSizeInBytes = encryptedFileBlockSizeInBytes; 73 | } 74 | 75 | public boolean isUseUniqueIV() { 76 | return useUniqueIV; 77 | } 78 | 79 | public void setUseUniqueIV(boolean useUniqueIV) { 80 | this.useUniqueIV = useUniqueIV; 81 | } 82 | 83 | public boolean isChainedNameIV() { 84 | return chainedNameIV; 85 | } 86 | 87 | public void setChainedNameIV(boolean chainedNameIV) { 88 | this.chainedNameIV = chainedNameIV; 89 | } 90 | 91 | public boolean isHolesAllowedInFiles() { 92 | return holesAllowedInFiles; 93 | } 94 | 95 | public void setHolesAllowedInFiles(boolean holesAllowedInFiles) { 96 | this.holesAllowedInFiles = holesAllowedInFiles; 97 | } 98 | 99 | public int getEncodedKeyLengthInBytes() { 100 | return encodedKeyLengthInBytes; 101 | } 102 | 103 | public void setEncodedKeyLengthInBytes(int encodedKeyLengthInBytes) { 104 | this.encodedKeyLengthInBytes = encodedKeyLengthInBytes; 105 | } 106 | 107 | public String getBase64EncodedVolumeKey() { 108 | return base64EncodedVolumeKey; 109 | } 110 | 111 | public void setBase64EncodedVolumeKey(String base64EncodedVolumeKey) { 112 | this.base64EncodedVolumeKey = base64EncodedVolumeKey; 113 | } 114 | 115 | public int getSaltLengthBytes() { 116 | return saltLengthBytes; 117 | } 118 | 119 | public void setSaltLengthBytes(int saltLengthBytes) { 120 | this.saltLengthBytes = saltLengthBytes; 121 | } 122 | 123 | public String getBase64Salt() { 124 | return base64Salt; 125 | } 126 | 127 | public void setBase64Salt(String salt) { 128 | this.base64Salt = salt; 129 | } 130 | 131 | public int getIterationForPasswordKeyDerivationCount() { 132 | return iterationForPasswordKeyDerivationCount; 133 | } 134 | 135 | public void setIterationForPasswordKeyDerivationCount( 136 | int iterationForPasswordKeyDerivationCount) { 137 | this.iterationForPasswordKeyDerivationCount = iterationForPasswordKeyDerivationCount; 138 | } 139 | 140 | public EncFSFilenameEncryptionAlgorithm getFilenameAlgorithm() { 141 | return filenameAlgorithm; 142 | } 143 | 144 | public void setFilenameAlgorithm( 145 | EncFSFilenameEncryptionAlgorithm filenameAlgorithm) { 146 | this.filenameAlgorithm = filenameAlgorithm; 147 | } 148 | 149 | public int getNumberOfMACBytesForEachFileBlock() { 150 | return numberOfMACBytesForEachFileBlock; 151 | } 152 | 153 | public void setNumberOfMACBytesForEachFileBlock( 154 | int numberOfMACBytesForEachFileBlock) { 155 | this.numberOfMACBytesForEachFileBlock = numberOfMACBytesForEachFileBlock; 156 | } 157 | 158 | public int getNumberOfRandomBytesInEachMACHeader() { 159 | return numberOfRandomBytesInEachMACHeader; 160 | } 161 | 162 | public void setNumberOfRandomBytesInEachMACHeader( 163 | int numberOfRandomBytesInEachMACHeader) { 164 | this.numberOfRandomBytesInEachMACHeader = numberOfRandomBytesInEachMACHeader; 165 | } 166 | 167 | public boolean isSupportedExternalIVChaining() { 168 | return supportedExternalIVChaining; 169 | } 170 | 171 | public void setSupportedExternalIVChaining( 172 | boolean supportedExternalIVChaining) { 173 | this.supportedExternalIVChaining = supportedExternalIVChaining; 174 | } 175 | 176 | public void validate() throws EncFSInvalidConfigException { 177 | if (isSupportedExternalIVChaining() 178 | && (!isChainedNameIV() || !isUseUniqueIV())) { 179 | throw new EncFSInvalidConfigException( 180 | "External IV chaining requires chained name IV and unique IV to be enabled"); 181 | } 182 | } 183 | 184 | @Override 185 | public String toString() { 186 | return "EncFSConfig [volumeKeySizeInBits=" + volumeKeySizeInBits 187 | + ", encryptedFileBlockSizeInBytes=" 188 | + encryptedFileBlockSizeInBytes + ", useUniqueIV=" 189 | + useUniqueIV + ", chainedNameIV=" + chainedNameIV 190 | + ", holesAllowedInFiles=" + holesAllowedInFiles 191 | + ", encodedKeyLengthInBytes=" + encodedKeyLengthInBytes 192 | + ", base64EncodedVolumeKey=" + base64EncodedVolumeKey 193 | + ", saltLengthBytes=" + saltLengthBytes + ", base64Salt=" 194 | + base64Salt + ", iterationForPasswordKeyDerivationCount=" 195 | + iterationForPasswordKeyDerivationCount + ", algorithm=" 196 | + filenameAlgorithm + ", numberOfMACBytesForEachFileBlock=" 197 | + numberOfMACBytesForEachFileBlock 198 | + ", numberOfRandomBytesInEachMACHeader=" 199 | + numberOfRandomBytesInEachMACHeader 200 | + ", supportedExternalIVChaining=" 201 | + supportedExternalIVChaining + "]"; 202 | } 203 | } -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSConfigFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | /** 18 | * Class for creating EncFSConfig objects 19 | */ 20 | public final class EncFSConfigFactory { 21 | 22 | /** 23 | * Creates an EncFSConfig with default parameters: 24 | * 25 | * nameio/block
26 | * 192-bit key
27 | * 1024 byte block size
28 | * Unique IV
29 | * Chained name IV
30 | * AllowHoles
31 | * 5000 PBKDF2 iterations
32 | * 33 | * @return An EncFSConfig object with default parameters 34 | */ 35 | public static EncFSConfig createDefault() { 36 | EncFSConfig config = new EncFSConfig(); 37 | config.setFilenameAlgorithm(EncFSFilenameEncryptionAlgorithm.BLOCK); 38 | config.setVolumeKeySizeInBits(192); 39 | config.setEncryptedFileBlockSizeInBytes(1024); 40 | config.setUseUniqueIV(true); 41 | config.setChainedNameIV(true); 42 | config.setHolesAllowedInFiles(true); 43 | config.setIterationForPasswordKeyDerivationCount(5000); 44 | config.setNumberOfMACBytesForEachFileBlock(0); 45 | config.setNumberOfRandomBytesInEachMACHeader(0); 46 | config.setSupportedExternalIVChaining(false); 47 | return config; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSConfigParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | import org.w3c.dom.Document; 19 | import org.w3c.dom.Node; 20 | import org.w3c.dom.NodeList; 21 | import org.xml.sax.SAXException; 22 | 23 | import javax.xml.parsers.DocumentBuilder; 24 | import javax.xml.parsers.DocumentBuilderFactory; 25 | import javax.xml.parsers.ParserConfigurationException; 26 | import java.io.File; 27 | import java.io.FileInputStream; 28 | import java.io.IOException; 29 | import java.io.InputStream; 30 | 31 | /** 32 | * Parser methods that read and interpret EncFS configuration files. 33 | */ 34 | public class EncFSConfigParser { 35 | 36 | private static String getNodeValue(Node n) { 37 | return n.getChildNodes().item(0).getNodeValue(); 38 | } 39 | 40 | /** 41 | * Parse the given configuration file 42 | * 43 | * @param configFile 44 | * EncFS volume configuration file. 45 | * @return An EncFSConfig object containing the configuration data 46 | * interpreted from the given file. 47 | */ 48 | public static EncFSConfig parseFile(File configFile) 49 | throws ParserConfigurationException, SAXException, IOException, 50 | EncFSInvalidConfigException, EncFSUnsupportedException { 51 | FileInputStream inputStream = new FileInputStream(configFile); 52 | try { 53 | return parseFile(inputStream); 54 | } finally { 55 | inputStream.close(); 56 | } 57 | 58 | } 59 | 60 | /** 61 | * Parse the configuration file residing on an EncFSFileProvider with the 62 | * given path 63 | * 64 | * @param fileProvider 65 | * File provider to access the config file 66 | * @param path 67 | * Path of the config file in the file provider's notation 68 | * @return An EncFSConfig object representing the parsing result 69 | */ 70 | public static EncFSConfig parseConfig(EncFSFileProvider fileProvider, 71 | String path) throws EncFSUnsupportedException, 72 | EncFSInvalidConfigException, IOException { 73 | 74 | EncFSConfig config; 75 | // TODO: Need to implement a connector method in EncFSFileProvider for 76 | // '/' 77 | if (!fileProvider.exists(fileProvider.getFilesystemRootPath() + path)) { 78 | // Try old versions 79 | for (String altConfigFileName : EncFSVolume.OLD_CONFIG_FILE_NAMES) { 80 | if (fileProvider.exists(fileProvider.getFilesystemRootPath() 81 | + altConfigFileName)) { 82 | throw new EncFSUnsupportedException( 83 | "Unsupported EncFS version"); 84 | } 85 | } 86 | 87 | throw new EncFSInvalidConfigException( 88 | "No EncFS configuration file found"); 89 | } 90 | 91 | // Parse the configuration file 92 | try { 93 | config = EncFSConfigParser.parseFile(fileProvider 94 | .openInputStream(fileProvider.getFilesystemRootPath() 95 | + path)); 96 | } catch (ParserConfigurationException e2) { 97 | throw new EncFSUnsupportedException("XML parser not supported"); 98 | } catch (SAXException e2) { 99 | throw new EncFSInvalidConfigException("Parse error in config file"); 100 | } catch (IOException e2) { 101 | throw new EncFSInvalidConfigException("Couldn't open config file"); 102 | } 103 | 104 | // Validate the configuration 105 | config.validate(); 106 | 107 | return config; 108 | } 109 | 110 | /** 111 | * Parse the given configuration file from a stream 112 | * 113 | * @param inputStream 114 | * InputStream for the config file 115 | * @return An EncFSConfig object containing the configuration data 116 | * interpreted from the given file. 117 | */ 118 | private static EncFSConfig parseFile(InputStream inputStream) 119 | throws ParserConfigurationException, SAXException, IOException, 120 | EncFSInvalidConfigException { 121 | EncFSConfig config = EncFSConfigFactory.createDefault(); 122 | 123 | DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 124 | DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); 125 | Document doc = dBuilder.parse(inputStream); 126 | doc.getDocumentElement().normalize(); 127 | 128 | NodeList cfgNodeList = doc.getElementsByTagName("cfg").item(0) 129 | .getChildNodes(); 130 | 131 | if (cfgNodeList.getLength() == 0) { 132 | throw new EncFSInvalidConfigException( 133 | " element not present in config file"); 134 | } 135 | 136 | for (int i = 0; i < cfgNodeList.getLength(); i++) { 137 | Node cfgNode = cfgNodeList.item(i); 138 | 139 | if (cfgNode.getNodeType() == Node.ELEMENT_NODE) { 140 | if (cfgNode.getNodeName().equals("nameAlg")) { 141 | NodeList nameAlgNodeList = cfgNode.getChildNodes(); 142 | for (int j = 0; j < nameAlgNodeList.getLength(); j++) { 143 | Node nameAlgChildNode = nameAlgNodeList.item(j); 144 | if (nameAlgChildNode.getNodeName().equals("name")) { 145 | String algName = getNodeValue(nameAlgChildNode); 146 | try { 147 | config.setFilenameAlgorithm(EncFSFilenameEncryptionAlgorithm 148 | .parse(algName)); 149 | } catch (IllegalArgumentException e) { 150 | throw new EncFSInvalidConfigException( 151 | "Unknown name algorithm in config file: " 152 | + algName); 153 | } 154 | } 155 | } 156 | } else if (cfgNode.getNodeName().equals("keySize")) { 157 | config.setVolumeKeySizeInBits(Integer 158 | .parseInt(getNodeValue(cfgNode))); 159 | } else if (cfgNode.getNodeName().equals("blockSize")) { 160 | config.setEncryptedFileBlockSizeInBytes(Integer 161 | .parseInt(getNodeValue(cfgNode))); 162 | } else if (cfgNode.getNodeName().equals("uniqueIV")) { 163 | config.setUseUniqueIV(Integer 164 | .parseInt(getNodeValue(cfgNode)) == 1); 165 | } else if (cfgNode.getNodeName().equals("chainedNameIV")) { 166 | config.setChainedNameIV(Integer 167 | .parseInt(getNodeValue(cfgNode)) == 1); 168 | } else if (cfgNode.getNodeName().equals("allowHoles")) { 169 | config.setHolesAllowedInFiles(Integer 170 | .parseInt(getNodeValue(cfgNode)) == 1); 171 | } else if (cfgNode.getNodeName().equals("encodedKeySize")) { 172 | config.setEncodedKeyLengthInBytes(Integer 173 | .parseInt(getNodeValue(cfgNode))); 174 | } else if (cfgNode.getNodeName().equals("encodedKeyData")) { 175 | config.setBase64EncodedVolumeKey(getNodeValue(cfgNode)); 176 | } else if (cfgNode.getNodeName().equals("saltLen")) { 177 | config.setSaltLengthBytes(Integer 178 | .parseInt(getNodeValue(cfgNode))); 179 | } else if (cfgNode.getNodeName().equals("saltData")) { 180 | config.setBase64Salt(getNodeValue(cfgNode)); 181 | } else if (cfgNode.getNodeName().equals("kdfIterations")) { 182 | config.setIterationForPasswordKeyDerivationCount(Integer 183 | .parseInt(getNodeValue(cfgNode))); 184 | } else if (cfgNode.getNodeName().equals("blockMACBytes")) { 185 | config.setNumberOfMACBytesForEachFileBlock(Integer 186 | .parseInt(getNodeValue(cfgNode))); 187 | } else if (cfgNode.getNodeName().equals("blockMACRandBytes")) { 188 | config.setNumberOfRandomBytesInEachMACHeader(Integer 189 | .parseInt(getNodeValue(cfgNode))); 190 | } else if (cfgNode.getNodeName().equals("externalIVChaining")) { 191 | config.setSupportedExternalIVChaining(Integer 192 | .parseInt(getNodeValue(cfgNode)) == 1); 193 | } 194 | } 195 | } 196 | 197 | return config; 198 | } 199 | } -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSConfigWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011-2012 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | import java.io.OutputStream; 21 | import java.util.Properties; 22 | 23 | /** 24 | * Writer methods that write an EncFSConfig into a file 25 | */ 26 | public class EncFSConfigWriter { 27 | 28 | // Version to use if the properties file can't be read 29 | private static final String ENCFS_JAVA_LIB_VERSION_DEV = "dev"; 30 | 31 | // Property file 32 | private static final String ENCFS_JAVA_LIB_PROPERTY_FILE = "library.properties"; 33 | 34 | // Property key for version 35 | private static final String ENCFS_JAVA_LIB_VERSION_KEY = "library.version"; 36 | 37 | // Retrieve library version 38 | private static String getLibraryVersion() { 39 | Properties prop = new Properties(); 40 | InputStream in = EncFSConfigWriter.class 41 | .getResourceAsStream(ENCFS_JAVA_LIB_PROPERTY_FILE); 42 | 43 | if (in != null) { 44 | try { 45 | prop.load(in); 46 | String version = prop.getProperty(ENCFS_JAVA_LIB_VERSION_KEY); 47 | if (version != null) { 48 | return version; 49 | } else { 50 | return ENCFS_JAVA_LIB_VERSION_DEV; 51 | } 52 | } catch (IOException e) { 53 | return ENCFS_JAVA_LIB_VERSION_DEV; 54 | } 55 | } else { 56 | return ENCFS_JAVA_LIB_VERSION_DEV; 57 | } 58 | } 59 | 60 | // Create config file contents from a given EncFSConfig / password 61 | private static String createConfigFileContents(EncFSConfig config) { 62 | // XXX: This implementation is pretty horrible, but it works :) 63 | String result = ""; 64 | 65 | result += "\n"; 66 | result += "\n"; 67 | result += "\n"; 68 | result += " \n"; 69 | result += "\t20100713\n"; 70 | result += "\tencfs-java " + getLibraryVersion() 71 | + "\n"; 72 | result += "\t\n"; 73 | result += "\t\tssl/aes\n"; 74 | result += "\t\t3\n"; 75 | result += "\t\t0\n"; 76 | result += "\t\n"; 77 | 78 | result += "\t\n"; 79 | 80 | EncFSFilenameEncryptionAlgorithm algorithm = config 81 | .getFilenameAlgorithm(); 82 | result += "\t\t" + algorithm.getIdentifier() + "\n"; 83 | result += "\t\t" + algorithm.getMajor() + "\n"; 84 | result += "\t\t" + algorithm.getMinor() + "\n"; 85 | 86 | result += "\t\n"; 87 | 88 | result += "\t" 89 | + Integer.toString(config.getVolumeKeySizeInBits()) 90 | + "\n"; 91 | 92 | result += "\t" 93 | + Integer.toString(config.getEncryptedFileBlockSizeInBytes()) 94 | + "\n"; 95 | 96 | result += "\t" + (config.isUseUniqueIV() ? "1" : "0") 97 | + "\n"; 98 | 99 | result += "\t" + (config.isChainedNameIV() ? "1" : "0") 100 | + "\n"; 101 | 102 | result += "\t" 103 | + (config.isSupportedExternalIVChaining() ? "1" : "0") 104 | + "\n"; 105 | 106 | result += "\t" 107 | + Integer 108 | .toString(config.getNumberOfMACBytesForEachFileBlock()) 109 | + "\n"; 110 | result += "\t" 111 | + Integer.toString(config 112 | .getNumberOfRandomBytesInEachMACHeader()) 113 | + "\n"; 114 | 115 | result += "\t" 116 | + (config.isHolesAllowedInFiles() ? "1" : "0") 117 | + "\n"; 118 | 119 | result += "\t" 120 | + Integer.toString(config.getEncodedKeyLengthInBytes()) 121 | + "\n"; 122 | result += "\t" + config.getBase64EncodedVolumeKey() 123 | + "\n\n"; 124 | 125 | result += "\t" + Integer.toString(config.getSaltLengthBytes()) 126 | + "\n"; 127 | result += "\t" + config.getBase64Salt() + "\n\n"; 128 | 129 | result += "\t" 130 | + Integer.toString(config 131 | .getIterationForPasswordKeyDerivationCount()) 132 | + "\n"; 133 | 134 | // XXX: We don't support custom KDF durations 135 | result += "\t500\n"; 136 | 137 | result += " \n"; 138 | result += "\n"; 139 | 140 | return result; 141 | } 142 | 143 | /** 144 | * Create a configuration file from the given EncFSConfig and write it to 145 | * the root directory of the given EncFSFileProvider 146 | */ 147 | public static void writeConfig(EncFSFileProvider fileProvider, 148 | EncFSConfig config) throws EncFSUnsupportedException, IOException { 149 | String configFileName = fileProvider.getFilesystemRootPath() 150 | + EncFSVolume.CONFIG_FILE_NAME; 151 | 152 | if (fileProvider.exists(configFileName)) { 153 | throw new EncFSUnsupportedException("Config file already exists"); 154 | } 155 | 156 | String configFileContents = createConfigFileContents(config); 157 | 158 | OutputStream os = fileProvider.openOutputStream(configFileName, 159 | configFileContents.length()); 160 | 161 | os.write(configFileContents.getBytes()); 162 | os.close(); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSCorruptDataException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | public class EncFSCorruptDataException extends EncFSException { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | public EncFSCorruptDataException(String message) { 23 | super(message); 24 | } 25 | 26 | public EncFSCorruptDataException(Throwable cause) { 27 | super(cause); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | public abstract class EncFSException extends Exception { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | EncFSException(String message) { 23 | super(message); 24 | } 25 | 26 | EncFSException(Throwable cause) { 27 | super(cause); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSFile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | import java.io.IOException; 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | /** 23 | * Object representing a file in an EncFS volume. 24 | *

25 | * Useful for decryption of file names as well as performing file operations 26 | * such as copying, moving, deletion etc. 27 | */ 28 | public class EncFSFile { 29 | 30 | /** 31 | * Size in bytes of file header when file IV's are used (uniqueIV) 32 | */ 33 | public static final int HEADER_SIZE = 8; 34 | 35 | // Volume hosting this file 36 | private final EncFSVolume volume; 37 | 38 | // Information about the plaintext file (decoded names etc.) 39 | private final EncFSFileInfo plainFileInfo; 40 | 41 | // Information about the ciphertext file (encrypted names etc.) 42 | private final EncFSFileInfo cipherFileInfo; 43 | 44 | /** 45 | * Create a new object representing a file in an EncFS volume 46 | * 47 | * @param volume 48 | * The volume that contains the file 49 | * @param plainFileInfo 50 | * EncFSFileInfo representing the cleartext file (decoded) 51 | * @param cipherFileInfo 52 | * EncFSFileInfo representing the ciphertext file (encoded) 53 | */ 54 | public EncFSFile(EncFSVolume volume, EncFSFileInfo plainFileInfo, 55 | EncFSFileInfo cipherFileInfo) { 56 | this.volume = volume; 57 | this.plainFileInfo = plainFileInfo; 58 | this.cipherFileInfo = cipherFileInfo; 59 | } 60 | 61 | /** 62 | * Returns the volume path of this file 63 | * 64 | * @return Absolute volume path of the file 65 | */ 66 | public String getPath() { 67 | return plainFileInfo.getPath(); 68 | } 69 | 70 | /** 71 | * Returns the encrypted volume path of this file 72 | * 73 | * @return Encrypted volume path of the file 74 | */ 75 | public String getEncryptedPath() { 76 | return cipherFileInfo.getPath(); 77 | } 78 | 79 | /** 80 | * Returns the volume path of the parent directory hosting this file 81 | *

82 | * This is the plaintext path starting from the volume's root up until the 83 | * parent directory hosting the current file 84 | * 85 | * @return Volume path of this file's parent directory 86 | */ 87 | public String getParentPath() { 88 | return plainFileInfo.getParentPath(); 89 | } 90 | 91 | /** 92 | * Returns the encrypted volume path of the parent directory hosting this 93 | * file 94 | * 95 | * @return Encrypted volume path of this file's parent directory 96 | */ 97 | public String getEncryptedParentPath() { 98 | return cipherFileInfo.getParentPath(); 99 | } 100 | 101 | /** 102 | * Returns the plaintext name of this file 103 | * 104 | * @return decrypted name of this EncFS file 105 | */ 106 | public String getName() { 107 | return plainFileInfo.getName(); 108 | } 109 | 110 | /** 111 | * Returns the ciphertext name of this file 112 | * 113 | * @return encrypted name of this EncFS file 114 | */ 115 | public String getEncrytedName() { 116 | return cipherFileInfo.getName(); 117 | } 118 | 119 | /** 120 | * Returns the length of decrypted contents for this file 121 | * 122 | * @return Length of decrypted file contents 123 | */ 124 | public long getLength() { 125 | return plainFileInfo.getSize(); 126 | } 127 | 128 | /** 129 | * Returns the last modification time for this file 130 | * 131 | * @return last modification time for the file 132 | */ 133 | public long getLastModified() { 134 | return plainFileInfo.getLastModified(); 135 | } 136 | 137 | /** 138 | * Returns the volume containing this file 139 | * 140 | * @return Volume containing the EncFS file 141 | */ 142 | public EncFSVolume getVolume() { 143 | return volume; 144 | } 145 | 146 | /** 147 | * Checks whether this EncFSFile represents a directory 148 | * 149 | * @return true if directory, false otherwise 150 | */ 151 | public boolean isDirectory() { 152 | return plainFileInfo.isDirectory(); 153 | } 154 | 155 | /** 156 | * Checks whether the file is readable 157 | * 158 | * @return true if the file is readable, false otherwise 159 | */ 160 | public boolean isReadable() { 161 | return plainFileInfo.isReadable(); 162 | } 163 | 164 | /** 165 | * Checks whether the file is writable 166 | * 167 | * @return true if the file is writable, false otherwise 168 | */ 169 | public boolean isWritable() { 170 | return plainFileInfo.isWritable(); 171 | } 172 | 173 | /** 174 | * Checks whether the file is executable 175 | * 176 | * @return true if the file is executable, false otherwise 177 | */ 178 | public boolean isExecutable() { 179 | return plainFileInfo.isExecutable(); 180 | } 181 | 182 | /** 183 | * List files/directory names contained by the directory represented by this 184 | * EncFSFile object. 185 | */ 186 | public String[] list() throws IOException { 187 | EncFSFile[] files = listFiles(); 188 | 189 | String[] fileNames = null; 190 | if (files != null) { 191 | fileNames = new String[files.length]; 192 | 193 | for (int i = 0; i < files.length; i++) { 194 | EncFSFile file = files[i]; 195 | fileNames[i] = file.getName(); 196 | } 197 | } 198 | 199 | return fileNames; 200 | } 201 | 202 | /** 203 | * Get list of EncFSFile's under this directory 204 | * 205 | * @return list of EncFSFile under the given directory 206 | */ 207 | public EncFSFile[] listFiles() throws IOException { 208 | 209 | if (!isDirectory()) { 210 | return null; 211 | } 212 | 213 | String encDirName; 214 | if (this == volume.getRootDir()) { 215 | encDirName = EncFSVolume.ROOT_PATH; 216 | } else { 217 | encDirName = getEncryptedPath(); 218 | } 219 | String dirName = getPath(); 220 | 221 | List fileInfos = volume.getFileProvider().listFiles( 222 | encDirName); 223 | List result = new ArrayList(fileInfos.size()); 224 | 225 | for (EncFSFileInfo fileInfo : fileInfos) { 226 | String decodedFileName; 227 | try { 228 | decodedFileName = EncFSCrypto.decodeName(volume, 229 | fileInfo.getName(), dirName); 230 | } catch (EncFSCorruptDataException e) { 231 | decodedFileName = null; 232 | } catch (EncFSChecksumException e) { 233 | decodedFileName = null; 234 | } 235 | 236 | if (decodedFileName != null) { 237 | EncFSFileInfo decEncFileInfo = EncFSFileInfo 238 | .getDecodedFileInfo(volume, dirName, decodedFileName, 239 | fileInfo); 240 | 241 | result.add(new EncFSFile(volume, decEncFileInfo, fileInfo)); 242 | } 243 | } 244 | 245 | return result.toArray(new EncFSFile[result.size()]); 246 | } 247 | 248 | /** 249 | * Delete this file 250 | * 251 | * @return true if deletion succeeds, false otherwise 252 | */ 253 | public boolean delete() throws IOException { 254 | return volume.getFileProvider().delete(getEncryptedPath()); 255 | } 256 | 257 | /** 258 | * Opens the file as an EncFSInputStream that decodes the file contents 259 | * automatically 260 | * 261 | * @return EncFSInputStream that decodes file contents 262 | */ 263 | public EncFSInputStream openInputStream() throws EncFSCorruptDataException, 264 | EncFSUnsupportedException, IOException { 265 | return new EncFSInputStream(volume, volume.getFileProvider() 266 | .openInputStream(getEncryptedPath()), getPath()); 267 | } 268 | 269 | /** 270 | * Opens the file as an EncFSOutputStream that encrypts the file contents 271 | * automatically 272 | * 273 | * @param inputLength 274 | * Length of the input file that will be written to this output 275 | * stream. Note that this parameter is optional if using 276 | * EncFSLocalFileProvider, but some network based storage API's 277 | * require knowing the file length in advance. 278 | * @return EncFSOutputStream that encrypts file contents 279 | */ 280 | public EncFSOutputStream openOutputStream(long inputLength) 281 | throws EncFSUnsupportedException, EncFSCorruptDataException, 282 | IOException { 283 | return new EncFSOutputStream(volume, volume.getFileProvider() 284 | .openOutputStream(getEncryptedPath(), 285 | volume.getEncryptedFileLength(inputLength)), getPath()); 286 | } 287 | 288 | /** 289 | * Copies this file/dir to a target file or directory 290 | * 291 | * @param dstPath 292 | * EncFSFile representing the target file or directory 293 | * @return true if copy succeeds, false otherwise 294 | */ 295 | public boolean copy(EncFSFile dstPath) throws IOException { 296 | if (isDirectory()) { 297 | // Recursive copy of this directory to the target path 298 | try { 299 | return volume.copyPath(getPath(), dstPath.getPath()); 300 | } catch (EncFSCorruptDataException e) { 301 | throw new IOException(e); 302 | } 303 | } else if (dstPath.isDirectory()) { 304 | /* 305 | * Trying to copy a file to a directory, copy it UNDER that 306 | * directory instead 307 | */ 308 | EncFSFile realDstPath; 309 | try { 310 | realDstPath = volume.createFile(dstPath.getPath(), getName()); 311 | } catch (EncFSCorruptDataException e) { 312 | throw new IOException(e); 313 | } 314 | return copy(realDstPath); 315 | } else { 316 | // Trying to copy a file into a file 317 | if (volume.getConfig().isSupportedExternalIVChaining()) { 318 | /* 319 | * Need to re-encrypt the file since external IV chaining is 320 | * used. 321 | */ 322 | try { 323 | EncFSUtil.copyWholeStreamAndClose(openInputStream(), 324 | dstPath.openOutputStream(getLength())); 325 | } catch (EncFSException e) { 326 | throw new IOException(e); 327 | } 328 | return true; 329 | } else { 330 | // Simply copy the file using the file provider 331 | return volume.getFileProvider().copy(getEncryptedPath(), 332 | dstPath.getEncryptedPath()); 333 | } 334 | } 335 | } 336 | } -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSFileInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | /** 19 | * Class representing information about an underlying file 20 | */ 21 | public class EncFSFileInfo { 22 | // Name of the file 23 | private final String name; 24 | 25 | // Volume path of the parent directory hosting the file 26 | private final String parentPath; 27 | 28 | // Whether the file is a directory 29 | private final boolean directory; 30 | 31 | // Last modification time of the file 32 | private final long lastModified; 33 | 34 | // Raw size of the underlying file 35 | private final long size; 36 | 37 | // Whether the file is readable 38 | private final boolean readable; 39 | 40 | // Whether the file is writable 41 | private final boolean writable; 42 | 43 | // Whether the file is executable 44 | private final boolean executable; 45 | 46 | /** 47 | * Create a new EncFSFileInfo 48 | * 49 | * @param name 50 | * Name of the file 51 | * @param parentPath 52 | * Volume path of the parent directory hosting the file 53 | * @param directory 54 | * Whether the file is a directory 55 | * @param lastModified 56 | * Last modification time of the file 57 | * @param size 58 | * Raw size of the underlying file 59 | * @param readable 60 | * Whether the file is readable 61 | * @param writable 62 | * Whether the file is writable 63 | * @param executable 64 | * Whether the file is executable 65 | */ 66 | public EncFSFileInfo(String name, String parentPath, boolean directory, 67 | long lastModified, long size, boolean readable, boolean writable, 68 | boolean executable) { 69 | if (name.startsWith(EncFSVolume.PATH_SEPARATOR) 70 | && (!name.equals(EncFSVolume.ROOT_PATH))) { 71 | throw new IllegalArgumentException("Invalid name " + name); 72 | } 73 | 74 | this.name = name; 75 | this.parentPath = parentPath; 76 | this.directory = directory; 77 | this.lastModified = lastModified; 78 | this.size = size; 79 | this.readable = readable; 80 | this.writable = writable; 81 | this.executable = executable; 82 | } 83 | 84 | /** 85 | * Returns the name of the file 86 | * 87 | * @return name of the file 88 | */ 89 | public String getName() { 90 | return name; 91 | } 92 | 93 | /** 94 | * Returns the volume path of the parent directory hosting the file 95 | * 96 | * @return volume path of the parent directory hosting the file 97 | */ 98 | public String getParentPath() { 99 | return parentPath; 100 | } 101 | 102 | /** 103 | * Returns the volume path of the file 104 | * 105 | * @return volume path of the file 106 | */ 107 | public String getPath() { 108 | String result; 109 | 110 | if (parentPath.endsWith(EncFSVolume.PATH_SEPARATOR) 111 | || name.startsWith(EncFSVolume.PATH_SEPARATOR)) { 112 | result = parentPath + name; 113 | } else { 114 | result = EncFSVolume.combinePath(parentPath, name); 115 | } 116 | 117 | return result; 118 | } 119 | 120 | /** 121 | * Returns the last modification time of the file 122 | * 123 | * @return last modification time of the file 124 | */ 125 | public long getLastModified() { 126 | return lastModified; 127 | } 128 | 129 | /** 130 | * Returns the raw size of the underlying file 131 | * 132 | * @return raw size of the underlying file 133 | */ 134 | public long getSize() { 135 | return size; 136 | } 137 | 138 | /** 139 | * Returns whether the file is a directory 140 | * 141 | * @return whether the file is a directory 142 | */ 143 | public boolean isDirectory() { 144 | return directory; 145 | } 146 | 147 | /** 148 | * Returns whether the file is readable 149 | * 150 | * @return whether the file is readable 151 | */ 152 | public boolean isReadable() { 153 | return readable; 154 | } 155 | 156 | /** 157 | * Returns whether the file is writable 158 | * 159 | * @return whether the file is writable 160 | */ 161 | public boolean isWritable() { 162 | return writable; 163 | } 164 | 165 | /** 166 | * Returns whether the file is executable 167 | * 168 | * @return whether the file is executable 169 | */ 170 | public boolean isExecutable() { 171 | return executable; 172 | } 173 | 174 | /** 175 | * Produces an EncFSFileInfo for the decoded version of the file represented 176 | * by this object 177 | * 178 | * @param volume 179 | * Volume hosting this file 180 | * @param decodedParentPath 181 | * Decoded path of the parent directory for the output file 182 | * @param decodedFileName 183 | * Decoded file name of the output file 184 | * @param fileInfo 185 | * EncFSFileInfo for the file to be decoded 186 | * @return EncFSFileInfo for the decoded file 187 | */ 188 | public static EncFSFileInfo getDecodedFileInfo(EncFSVolume volume, 189 | String decodedParentPath, String decodedFileName, 190 | EncFSFileInfo fileInfo) { 191 | long size; 192 | if (fileInfo.isDirectory()) { 193 | size = 0; 194 | } else { 195 | size = volume.getDecryptedFileLength(fileInfo.getSize()); 196 | } 197 | 198 | return new EncFSFileInfo(decodedFileName, decodedParentPath, 199 | fileInfo.isDirectory(), fileInfo.getLastModified(), size, 200 | fileInfo.isReadable(), fileInfo.isWritable(), 201 | fileInfo.isExecutable()); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSFileInputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | import java.io.FilterInputStream; 19 | import java.io.IOException; 20 | 21 | /** 22 | * FileInputStream abstraction that allows decrypted data to be read from a file 23 | * on an EncFS volume. 24 | */ 25 | public class EncFSFileInputStream extends FilterInputStream { 26 | 27 | /** 28 | * Creates an EncFSFileInputStream to read decrypted data from a file under 29 | * and EncFS volume 30 | * 31 | * @param encfsFile 32 | * EncFSFile to open an input stream for 33 | *

34 | *

35 | * Filename encoding failed 36 | *

37 | * File header uses an unsupported IV length 38 | *

39 | * File provider returned I/O error 40 | */ 41 | public EncFSFileInputStream(EncFSFile encfsFile) 42 | throws EncFSCorruptDataException, EncFSUnsupportedException, 43 | IOException { 44 | super(encfsFile.openInputStream()); 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSFileOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | import java.io.FilterOutputStream; 18 | import java.io.IOException; 19 | 20 | /** 21 | * FilterOutputStream abstraction that allows writing encrypted data to a file 22 | * on an EncFS volume. 23 | */ 24 | public class EncFSFileOutputStream extends FilterOutputStream { 25 | 26 | /** 27 | * Creates an EncFSFileOutputStream to write encrypted data to a file under 28 | * and EncFS volume 29 | * 30 | * @param encfsFile 31 | * EncFSFile to open an output stream to 32 | * @param inputLength 33 | * Length of the input file that will be written to this output 34 | * stream. Note that this parameter is optional if using 35 | * EncFSLocalFileProvider, but some network based storage API's 36 | * require knowing the file length in advance. 37 | */ 38 | public EncFSFileOutputStream(EncFSFile encfsFile, long inputLength) 39 | throws IOException, EncFSUnsupportedException, 40 | EncFSCorruptDataException { 41 | super(encfsFile.openOutputStream(inputLength)); 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSFileProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | import java.io.OutputStream; 21 | import java.util.List; 22 | 23 | /** 24 | * An EncFSFileProvider provides an abstraction for accessing file contents and 25 | * information in their encrypted form on a local disk or any other storage 26 | * type. This class can be extended to implement EncFS functionality on 27 | * non-local storage. For local storage access, see the built-in file provider 28 | * class EncFSLocalFileProvider. 29 | */ 30 | public interface EncFSFileProvider { 31 | 32 | /** 33 | * Returns whether the given source path represents a directory in the 34 | * underlying filesystem 35 | * 36 | * @param srcPath 37 | * Path of the source file or directory 38 | * 39 | * @return true if path represents a directory, false otherwise 40 | * 41 | * @throws IOException 42 | * Source file/dir doesn't exist or misc. I/O error 43 | */ 44 | boolean isDirectory(String srcPath) throws IOException; 45 | 46 | /** 47 | * Returns whether the file or directory exists 48 | * 49 | * @param srcPath 50 | * Path of the file or directory 51 | * 52 | * @return true if file or directory exists, false otherwise 53 | * 54 | * @throws IOException 55 | * Misc. I/O error 56 | */ 57 | boolean exists(String srcPath) throws IOException; 58 | 59 | /** 60 | * Returns the root path for the underlying filesystem 61 | * 62 | * @return String representing the root path 63 | */ 64 | String getFilesystemRootPath(); 65 | 66 | /** 67 | * Return EncFSFileInfo for the given file or directory 68 | * 69 | * @param srcPath 70 | * Path of the file or directory 71 | * 72 | * @return EncFSFileInfo for the given file or directory 73 | * 74 | * @throws IOException 75 | * Path doesn't exist or misc. I/O error 76 | */ 77 | EncFSFileInfo getFileInfo(String srcPath) throws IOException; 78 | 79 | /** 80 | * Returns the list of files under the given directory path 81 | * 82 | * @param dirPath 83 | * Path of the directory to list files from 84 | * 85 | * @return a List of EncFSFileInfo representing files under the dir 86 | * 87 | * @throws IOException 88 | * Path not a directory or misc. I/O error 89 | */ 90 | List listFiles(String dirPath) throws IOException; 91 | 92 | /** 93 | * Move a file/directory to a different location 94 | * 95 | * @param srcPath 96 | * Path to the source file or directory 97 | * @param dstPath 98 | * Path for the destination file or directory 99 | * 100 | * @return true if the move is successful, false otherwise 101 | * 102 | * @throws IOException 103 | * Source file/dir doesn't exist or misc. I/O error 104 | */ 105 | boolean move(String srcPath, String dstPath) throws IOException; 106 | 107 | /** 108 | * Delete the file or directory with the given path 109 | * 110 | * @param srcPath 111 | * Path of the source file or directory 112 | * 113 | * @return true if deletion is successful, false otherwise 114 | * 115 | * @throws IOException 116 | * Source file/dir doesn't exist or misc. I/O error 117 | */ 118 | boolean delete(String srcPath) throws IOException; 119 | 120 | /** 121 | * Create a directory with the given path 122 | *

123 | * Note that all path elements except the last one must exist for this 124 | * method. If that is not true mkdirs should be used instead 125 | */ 126 | boolean mkdir(String dirPath) throws IOException; 127 | 128 | /** 129 | * Create a directory with the given path 130 | *

131 | * Intermediate directories are also created by this method 132 | */ 133 | boolean mkdirs(String dirPath) throws IOException; 134 | 135 | /** 136 | * Create a file with the given path 137 | * 138 | * @param dstFilePath 139 | * Path for the file to create 140 | * 141 | * @return EncFSFileInfo for the created file 142 | * 143 | * @throws IOException 144 | * File already exists or misc. I/O error 145 | */ 146 | EncFSFileInfo createFile(String dstFilePath) throws IOException; 147 | 148 | /** 149 | * Copy the file with the given path to another destination 150 | * 151 | * @param srcFilePath 152 | * Path to the file to copy 153 | * @param dstFilePath 154 | * Path to the destination file 155 | * 156 | * @return true if copy was successful, false otherwise 157 | * 158 | * @throws IOException 159 | * Destination file already exists, source file doesn't exist or 160 | * misc. I/O error 161 | */ 162 | boolean copy(String srcFilePath, String dstFilePath) throws IOException; 163 | 164 | /** 165 | * Open an InputStream to the given file 166 | * 167 | * @param srcFilePath 168 | * Path to the source file 169 | * 170 | * @return InputStream to read from the file 171 | * 172 | * @throws IOException 173 | * Source file doesn't exist or misc. I/O error 174 | */ 175 | InputStream openInputStream(String srcFilePath) throws IOException; 176 | 177 | /** 178 | * Open an OutputStream to the given file 179 | * 180 | * @param dstFilePath 181 | * Path to the destination file 182 | * @param outputLength 183 | * Length in bytes of the stream that will be written to this 184 | * stream. It is up to the file provider to determine whether 185 | * this parameter is optional or required. 186 | * 187 | * @return OutputStream to write to the file 188 | * 189 | * @throws IOException 190 | * Misc. I/O error 191 | */ 192 | OutputStream openOutputStream(String dstFilePath, long outputLength) 193 | throws IOException; 194 | } 195 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSFilenameEncryptionAlgorithm.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | /** 18 | * Enum representing the filename encryption algorithms used in EncFS 19 | */ 20 | public enum EncFSFilenameEncryptionAlgorithm { 21 | BLOCK("nameio/block", 3, 0), STREAM("nameio/stream", 2, 1), NULL( 22 | "nameio/null", 1, 0); 23 | 24 | private final String identifier; 25 | private final int major; 26 | private final int minor; 27 | 28 | EncFSFilenameEncryptionAlgorithm(String identifier, int major, int minor) { 29 | this.identifier = identifier; 30 | this.major = major; 31 | this.minor = minor; 32 | } 33 | 34 | /** 35 | * Parse the given string and return the corresponding algorithm value 36 | * 37 | * @param identifier 38 | * String to parse 39 | * 40 | * @return EncFSFileNameEncryptionAlgorithm corresponding to the string. 41 | */ 42 | public static EncFSFilenameEncryptionAlgorithm parse(String identifier) { 43 | for (EncFSFilenameEncryptionAlgorithm a : values()) { 44 | if (a.identifier.equals(identifier)) { 45 | return a; 46 | } 47 | } 48 | throw new IllegalArgumentException("could not parse: " + identifier); 49 | } 50 | 51 | public int getMajor() { 52 | return major; 53 | } 54 | 55 | public int getMinor() { 56 | return minor; 57 | } 58 | 59 | public String getIdentifier() { 60 | return identifier; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSInputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | import javax.crypto.BadPaddingException; 19 | import javax.crypto.IllegalBlockSizeException; 20 | import java.io.FilterInputStream; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.security.InvalidAlgorithmParameterException; 24 | 25 | /** 26 | * FilterInputStream extension that allows decrypted data to be read from a file 27 | * on an EncFS volume. 28 | */ 29 | public class EncFSInputStream extends FilterInputStream { 30 | 31 | // Volume that underlying file belongs to 32 | private final EncFSVolume volume; 33 | 34 | // Volume configuration for this file 35 | private final EncFSConfig config; 36 | 37 | // Cached block size for this volume 38 | private final int blockSize; 39 | 40 | // Number of MAC bytes for each block 41 | private final int numMACBytes; 42 | 43 | // Size of the block header for each block 44 | private final int blockHeaderSize; 45 | 46 | // Current block number for generating block IV 47 | private int blockNum; 48 | 49 | // Buffer containing decrypted data from the current block 50 | private byte[] blockBuf; 51 | 52 | // Cursor into blockBuf denoting current stream position 53 | private int bufCursor; 54 | 55 | // File IV computed from the first 8 bytes of the file 56 | private byte[] fileIv; 57 | 58 | /** 59 | * Create a new EncFSInputStream for reading decrypted data off a file on an 60 | * EncFS volume 61 | * 62 | * @param volume 63 | * Volume hosting the file to read 64 | * @param in 65 | * Input stream to access the raw (encrypted) file contents 66 | * @param volumePath 67 | * Volume path of the file being decrypted (needed for 68 | * externalIVChaining) 69 | */ 70 | public EncFSInputStream(EncFSVolume volume, InputStream in, 71 | String volumePath) throws EncFSCorruptDataException, 72 | EncFSUnsupportedException { 73 | super(in); 74 | this.volume = volume; 75 | this.config = volume.getConfig(); 76 | this.blockSize = config.getEncryptedFileBlockSizeInBytes(); 77 | this.numMACBytes = config.getNumberOfMACBytesForEachFileBlock(); 78 | int numRandBytes = config.getNumberOfRandomBytesInEachMACHeader(); 79 | this.blockHeaderSize = this.numMACBytes + numRandBytes; 80 | this.blockBuf = null; 81 | this.bufCursor = 0; 82 | this.blockNum = 0; 83 | 84 | if (config.isUseUniqueIV()) { 85 | // Compute file IV 86 | byte[] fileHeader = new byte[EncFSFile.HEADER_SIZE]; 87 | try { 88 | in.read(fileHeader); 89 | } catch (IOException e) { 90 | throw new EncFSCorruptDataException("Could't read file IV"); 91 | } 92 | 93 | byte[] initIv; 94 | if (config.isSupportedExternalIVChaining()) { 95 | /* 96 | * When using external IV chaining we compute initIv based on 97 | * the file path. 98 | */ 99 | initIv = StreamCrypto.computeChainIv(volume, volumePath); 100 | } else { 101 | // When not using external IV chaining initIv is just zero's. 102 | initIv = new byte[8]; 103 | } 104 | 105 | try { 106 | this.fileIv = StreamCrypto.streamDecrypt(volume, initIv, 107 | fileHeader); 108 | } catch (InvalidAlgorithmParameterException e) { 109 | e.printStackTrace(); 110 | } catch (IllegalBlockSizeException e) { 111 | throw new EncFSCorruptDataException(e); 112 | } catch (BadPaddingException e) { 113 | throw new EncFSCorruptDataException(e); 114 | } 115 | } else { 116 | // No unique IV per file, just use 0 117 | this.fileIv = new byte[EncFSFile.HEADER_SIZE]; 118 | } 119 | } 120 | 121 | /* 122 | * (non-Javadoc) 123 | * 124 | * @see java.io.FileInputStream#read() 125 | */ 126 | @Override 127 | public int read() throws IOException { 128 | byte[] oneByte = new byte[1]; 129 | int ret = this.read(oneByte, 0, 1); 130 | if (ret == 1) { 131 | return oneByte[0] & 0xFF; 132 | } 133 | return -1; 134 | } 135 | 136 | /* 137 | * (non-Javadoc) 138 | * 139 | * @see java.io.FileInputStream#read(byte[]) 140 | */ 141 | @Override 142 | public int read(byte[] b) throws IOException { 143 | return read(b, 0, b.length); 144 | } 145 | 146 | /* 147 | * (non-Javadoc) 148 | * 149 | * @see java.io.InputStream#read(byte[], int, int) 150 | */ 151 | @Override 152 | public int read(byte[] output, int offset, int size) throws IOException { 153 | int bytesRead = 0; 154 | int destOffset = offset; 155 | int bytesToCopy; 156 | int ret; 157 | 158 | while (bytesRead < size) { 159 | 160 | // Read more data if the data buffer is out 161 | if ((blockBuf == null) || (bufCursor == (blockBuf.length))) { 162 | try { 163 | ret = readBlock(); 164 | } catch (EncFSCorruptDataException e) { 165 | throw new IOException(e); 166 | } catch (EncFSUnsupportedException e) { 167 | throw new IOException(e); 168 | } 169 | 170 | if (ret < 0) { 171 | if (bytesRead == 0) { 172 | return -1; 173 | } else { 174 | return bytesRead; 175 | } 176 | } 177 | } 178 | 179 | bytesToCopy = Math.min(blockBuf.length - bufCursor, size 180 | - bytesRead); 181 | System.arraycopy(blockBuf, bufCursor, output, destOffset, 182 | bytesToCopy); 183 | 184 | bufCursor += bytesToCopy; 185 | bytesRead += bytesToCopy; 186 | destOffset += bytesToCopy; 187 | } 188 | 189 | return bytesRead; 190 | } 191 | 192 | /* 193 | * (non-Javadoc) 194 | * 195 | * @see java.io.FileInputStream#skip(long) 196 | */ 197 | @Override 198 | public long skip(long n) throws IOException { 199 | long bytesSkipped = 0; 200 | int toSkip; 201 | int bytesRead; 202 | 203 | byte[] skipBuf = new byte[config.getEncryptedFileBlockSizeInBytes()]; 204 | 205 | if (n < 0) { 206 | throw new IOException("Negative skip count"); 207 | } 208 | 209 | while (bytesSkipped < n) { 210 | toSkip = (int) Math.min(n - bytesSkipped, 211 | config.getEncryptedFileBlockSizeInBytes()); 212 | bytesRead = this.read(skipBuf, 0, toSkip); 213 | bytesSkipped += bytesRead; 214 | if (bytesRead == -1) { 215 | return -1; // Already at EOF 216 | } else if (bytesRead < toSkip) { 217 | return bytesSkipped; // Hit EOF now 218 | } 219 | } 220 | 221 | return bytesSkipped; 222 | } 223 | 224 | /* 225 | * (non-Javadoc) 226 | * 227 | * @see java.io.InputStream#markSupported() 228 | */ 229 | @Override 230 | public boolean markSupported() { 231 | // TODO: could support mark()/reset() 232 | return false; 233 | } 234 | 235 | // Return the block IV for the current block 236 | private byte[] getBlockIV() { 237 | long fileIvLong = EncFSUtil.convertByteArrayToLong(fileIv); 238 | return EncFSUtil.convertLongToByteArrayBigEndian(blockNum ^ fileIvLong); 239 | } 240 | 241 | /* 242 | * Read one block (blockSize bytes) of data from the underlying 243 | * FileInputStream, decrypt it and store it in blockBuf for consumption via 244 | * read() methods 245 | */ 246 | private int readBlock() throws IOException, EncFSCorruptDataException, 247 | EncFSUnsupportedException { 248 | byte[] cipherBuf = new byte[blockSize]; 249 | boolean zeroBlock = false; 250 | 251 | int bytesRead = 0; 252 | int lastBytesRead; 253 | 254 | // Read until we read a whole block or we reach the end of the input 255 | while (bytesRead < blockSize) { 256 | lastBytesRead = in 257 | .read(cipherBuf, bytesRead, blockSize - bytesRead); 258 | if (lastBytesRead > 0) { 259 | bytesRead += lastBytesRead; 260 | } else if (lastBytesRead < 0) { 261 | /* 262 | * If we read some bytes return that, if not then we're at the 263 | * end of the stream 264 | */ 265 | if (bytesRead == 0) { 266 | bytesRead = -1; 267 | } 268 | break; 269 | } 270 | } 271 | 272 | if (bytesRead == blockSize) { // block decode 273 | /* 274 | * If file holes are allowed then we need to test whether the whole 275 | * block is made up of 0's. If not (which is going to be the case 276 | * for MAC header by default), we will do block decryption. 277 | */ 278 | if (config.isHolesAllowedInFiles()) { 279 | zeroBlock = true; 280 | for (byte aCipherBuf : cipherBuf) 281 | if (aCipherBuf != 0) { 282 | zeroBlock = false; 283 | break; 284 | } 285 | } 286 | 287 | try { 288 | if (zeroBlock) { 289 | blockBuf = cipherBuf; 290 | } else { 291 | blockBuf = BlockCrypto.blockDecrypt(volume, getBlockIV(), 292 | cipherBuf); 293 | } 294 | } catch (InvalidAlgorithmParameterException e) { 295 | e.printStackTrace(); 296 | } catch (IllegalBlockSizeException e) { 297 | throw new EncFSCorruptDataException(e); 298 | } catch (BadPaddingException e) { 299 | throw new EncFSCorruptDataException(e); 300 | } 301 | 302 | bufCursor = blockHeaderSize; 303 | blockNum++; 304 | } else if (bytesRead > 0) { // stream decode 305 | try { 306 | blockBuf = StreamCrypto.streamDecrypt(volume, getBlockIV(), 307 | cipherBuf, 0, bytesRead); 308 | } catch (InvalidAlgorithmParameterException e) { 309 | e.printStackTrace(); 310 | } catch (IllegalBlockSizeException e) { 311 | throw new EncFSCorruptDataException(e); 312 | } catch (BadPaddingException e) { 313 | throw new EncFSCorruptDataException(e); 314 | } 315 | bufCursor = blockHeaderSize; 316 | blockNum++; 317 | } 318 | 319 | // Verify the block header 320 | if ((bytesRead > 0) && (blockHeaderSize > 0) && (!zeroBlock)) { 321 | byte mac[] = EncFSCrypto.mac64(volume.getMAC(), blockBuf, 322 | numMACBytes); 323 | for (int i = 0; i < numMACBytes; i++) { 324 | if (mac[7 - i] != blockBuf[i]) { 325 | throw new EncFSCorruptDataException("Block MAC mismatch"); 326 | } 327 | } 328 | } 329 | 330 | return bytesRead; 331 | } 332 | } 333 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSInvalidConfigException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | public class EncFSInvalidConfigException extends EncFSException { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | public EncFSInvalidConfigException(String message) { 23 | super(message); 24 | } 25 | 26 | public EncFSInvalidConfigException(Throwable cause) { 27 | super(cause); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSInvalidPasswordException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | public class EncFSInvalidPasswordException extends EncFSException { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | public EncFSInvalidPasswordException(Throwable cause) { 23 | super(cause); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSLocalFileProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | import java.io.*; 19 | import java.nio.channels.FileChannel; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | /** 24 | * Class implementing an EncFSFileProvider for accessing the local filesystem 25 | *

26 | * Note that all path parameters are relative to the rootPath provided to the 27 | * constructor. Thus, if one instantiates an EncFSFileProvider("/home/jdoe"), 28 | * the proper way to refer to /home/jdoe/dir/file.ext is by "dir/file.ext". 29 | */ 30 | public class EncFSLocalFileProvider implements EncFSFileProvider { 31 | 32 | private final String separator; 33 | 34 | private final File rootPath; 35 | 36 | public EncFSLocalFileProvider(File rootPath) { 37 | this.rootPath = rootPath; 38 | this.separator = File.separator; 39 | } 40 | 41 | /** 42 | * Returns whether the given source path represents a directory in the 43 | * underlying filesystem 44 | * 45 | * @param srcPath 46 | * Path of the source file or directory 47 | */ 48 | public boolean isDirectory(String srcPath) { 49 | File file = new File(rootPath.getAbsoluteFile(), srcPath); 50 | return file.isDirectory(); 51 | } 52 | 53 | /** 54 | * Get a File object representing the given path 55 | * 56 | * @param path 57 | * Path of the file or directory 58 | */ 59 | File getFile(String path) { 60 | return new File(rootPath.getAbsoluteFile(), path); 61 | } 62 | 63 | /** 64 | * Returns the path separator for the underlying filesystem 65 | * 66 | * @return String representing the path separator 67 | */ 68 | public final String getSeparator() { 69 | return separator; 70 | } 71 | 72 | /** 73 | * Returns the root path for the underlying filesystem 74 | * 75 | * @return String representing the root path 76 | */ 77 | public final String getFilesystemRootPath() { 78 | return "/"; 79 | } 80 | 81 | /** 82 | * Returns whether the file or directory exists 83 | * 84 | * @param srcPath 85 | * Path of the file or directory 86 | */ 87 | public boolean exists(String srcPath) { 88 | return new File(rootPath.getAbsoluteFile(), srcPath).exists(); 89 | } 90 | 91 | /** 92 | * Return EncFSFileInfo for the given file or directory 93 | * 94 | * @param srcPath 95 | * Path of the file or directory 96 | */ 97 | public EncFSFileInfo getFileInfo(String srcPath) { 98 | File sourceFile = new File(rootPath.getAbsoluteFile(), srcPath); 99 | return convertToFileInfo(sourceFile); 100 | } 101 | 102 | /** 103 | * Returns the list of files under the given directory path 104 | * 105 | * @param dirPath 106 | * Path of the directory to list files from 107 | */ 108 | public List listFiles(String dirPath) throws IOException { 109 | File srcDir = new File(rootPath.getAbsoluteFile(), dirPath); 110 | if (!srcDir.isDirectory()) { 111 | throw new IOException("Path: " + dirPath + " not a directory!"); 112 | } 113 | 114 | File[] files = srcDir.listFiles(); 115 | if (files == null) { 116 | /* 117 | * It's possible for a race condition to occur and srcDir to be 118 | * renamed or deleted between the isDirectory() check above and the 119 | * listFiles() call after it. We throw an exception in this case. 120 | */ 121 | throw new IOException("Path: " + dirPath + " was removed!"); 122 | } 123 | 124 | List results = new ArrayList(files.length); 125 | for (File file : files) { 126 | results.add(convertToFileInfo(file)); 127 | } 128 | return results; 129 | } 130 | 131 | /** 132 | * Move a file/directory to a different location 133 | * 134 | * @param srcPath 135 | * Path to the source file or directory 136 | * @param dstPath 137 | * Path for the destination file or directory 138 | */ 139 | public boolean move(String srcPath, String dstPath) throws IOException { 140 | File sourceFile = new File(rootPath.getAbsoluteFile(), srcPath); 141 | File destFile = new File(rootPath.getAbsoluteFile(), dstPath); 142 | 143 | if (!sourceFile.exists()) { 144 | throw new FileNotFoundException("Path '" + srcPath 145 | + "' doesn't exist!"); 146 | } 147 | 148 | return sourceFile.renameTo(destFile); 149 | } 150 | 151 | /* 152 | * Recursive delete function 153 | */ 154 | private void recursiveDelete(File file) throws IOException { 155 | if (file.isDirectory()) { 156 | for (File childFile : file.listFiles()) { 157 | recursiveDelete(childFile); 158 | } 159 | } 160 | if (!file.delete()) { 161 | throw new IOException("Failed to delete file " + file); 162 | } 163 | } 164 | 165 | /** 166 | * Delete the file or directory with the given path 167 | * 168 | * @param srcPath 169 | * Path of the source file or directory 170 | * @return true if deletion is successful, false otherwise 171 | */ 172 | public boolean delete(String srcPath) { 173 | File toEncFile = new File(rootPath.getAbsoluteFile(), srcPath); 174 | 175 | try { 176 | recursiveDelete(toEncFile); 177 | } catch (IOException e) { 178 | return false; 179 | } 180 | 181 | return true; 182 | } 183 | 184 | /** 185 | * Create a directory with the given path 186 | *

187 | * Note that all path elements except the last one must exist for this 188 | * method. If that is not true mkdirs should be used instead 189 | * 190 | * @param dirPath 191 | * Path to create a directory under 192 | */ 193 | public boolean mkdir(String dirPath) throws IOException { 194 | File file = new File(rootPath.getAbsoluteFile(), dirPath); 195 | File parentFile = file.getParentFile(); 196 | if (!parentFile.exists()) { 197 | throw new FileNotFoundException("Path '" 198 | + parentFile.getAbsolutePath() + "' doesn't exist!"); 199 | } 200 | return file.mkdir(); 201 | } 202 | 203 | /** 204 | * Create a directory with the given path 205 | *

206 | * Intermediate directories are also created by this method 207 | * 208 | * @param dirPath 209 | * Path to create a directory under 210 | */ 211 | public boolean mkdirs(String dirPath) { 212 | File toEncFile = new File(rootPath.getAbsoluteFile(), dirPath); 213 | return toEncFile.mkdirs(); 214 | } 215 | 216 | /** 217 | * Create a file with the given path 218 | * 219 | * @param dstFilePath 220 | * Path for the file to create 221 | * @return EncFSFileInfo for the created file 222 | */ 223 | public EncFSFileInfo createFile(String dstFilePath) throws IOException { 224 | if (exists(dstFilePath)) { 225 | throw new IOException("File already exists"); 226 | } 227 | 228 | File targetFile = getFile(dstFilePath); 229 | if (!targetFile.createNewFile()) { 230 | throw new IOException("failed to create new file"); 231 | } 232 | 233 | return convertToFileInfo(targetFile); 234 | } 235 | 236 | /** 237 | * Copy the file with the given path to another destination 238 | * 239 | * @param srcFilePath 240 | * Path to the file to copy 241 | * @param dstFilePath 242 | * Path to the destination file 243 | */ 244 | public boolean copy(String srcFilePath, String dstFilePath) 245 | throws IOException { 246 | 247 | File sourceFile = new File(rootPath.getAbsoluteFile(), srcFilePath); 248 | File destFile = new File(rootPath.getAbsoluteFile(), dstFilePath); 249 | 250 | if (!sourceFile.exists()) { 251 | throw new FileNotFoundException("Source file '" + srcFilePath 252 | + "' doesn't exist!"); 253 | } 254 | 255 | if (!destFile.exists()) { 256 | destFile.createNewFile(); 257 | } 258 | 259 | FileChannel source = null; 260 | FileChannel destination = null; 261 | 262 | try { 263 | source = new FileInputStream(sourceFile).getChannel(); 264 | destination = new FileOutputStream(destFile).getChannel(); 265 | destination.transferFrom(source, 0, source.size()); 266 | } finally { 267 | if (source != null) { 268 | source.close(); 269 | } 270 | if (destination != null) { 271 | destination.close(); 272 | } 273 | } 274 | 275 | return true; 276 | } 277 | 278 | /** 279 | * Open an InputStream to the given file 280 | * 281 | * @param srcFilePath 282 | * Path to the source file 283 | * @return InputStream to read from the file 284 | */ 285 | public InputStream openInputStream(String srcFilePath) 286 | throws FileNotFoundException { 287 | File srcF = new File(rootPath.getAbsoluteFile(), srcFilePath); 288 | return new FileInputStream(srcF); 289 | } 290 | 291 | /** 292 | * Open an OutputStream to the given file 293 | * 294 | * @param dstFilePath 295 | * Path to the destination file 296 | */ 297 | public OutputStream openOutputStream(String dstFilePath) throws IOException { 298 | return openOutputStream(dstFilePath, 0); 299 | } 300 | 301 | /** 302 | * Open an OutputStream to the given file 303 | * 304 | * @param dstFilePath 305 | * Path to the destination file 306 | * @param outputLength 307 | * Length in bytes of the stream that will be written to this 308 | * stream. It is ignored by this class. 309 | */ 310 | public OutputStream openOutputStream(String dstFilePath, long outputLength) 311 | throws IOException { 312 | File srcF = new File(rootPath.getAbsoluteFile(), dstFilePath); 313 | if (!srcF.exists()) { 314 | try { 315 | srcF.createNewFile(); 316 | } catch (Exception e) { 317 | throw new IOException(e); 318 | } 319 | } 320 | return new FileOutputStream(srcF); 321 | } 322 | 323 | // Convert the given File to an EncFSFileInfo 324 | private EncFSFileInfo convertToFileInfo(File file) { 325 | String relativePath; 326 | if (file.equals(rootPath.getAbsoluteFile())) { 327 | // we're dealing with the root dir 328 | relativePath = separator; 329 | } else if (file.getParentFile().equals(rootPath.getAbsoluteFile())) { 330 | // File is child of the root path 331 | relativePath = separator; 332 | } else { 333 | relativePath = file.getParentFile().getAbsolutePath() 334 | .substring(rootPath.getAbsoluteFile().toString().length()); 335 | } 336 | 337 | String name = file.getName(); 338 | return new EncFSFileInfo(name, relativePath, file.isDirectory(), 339 | file.lastModified(), file.length(), file.canRead(), 340 | file.canWrite(), file.canExecute()); 341 | } 342 | 343 | } 344 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | import javax.crypto.BadPaddingException; 19 | import javax.crypto.Cipher; 20 | import javax.crypto.IllegalBlockSizeException; 21 | import java.io.FilterOutputStream; 22 | import java.io.IOException; 23 | import java.io.OutputStream; 24 | import java.security.InvalidAlgorithmParameterException; 25 | import java.security.SecureRandom; 26 | import java.util.Arrays; 27 | 28 | /** 29 | * FilterOutputStream extension that allows encrypted data to be written to a 30 | * file on an EncFS volume. 31 | */ 32 | public class EncFSOutputStream extends FilterOutputStream { 33 | 34 | // SecureRandom instance for random data generation 35 | private static final SecureRandom secureRandom = new SecureRandom(); 36 | 37 | // Underlying volume 38 | private final EncFSVolume volume; 39 | 40 | // Volume configuration 41 | private final EncFSConfig config; 42 | 43 | // IV used for this file 44 | private byte[] fileIv; 45 | 46 | // Buffer to hold file header contents (uniqueIV) 47 | private byte[] fileHeader; 48 | 49 | // Buffer to hold the currently cached data contents to be written 50 | private final byte dataBuf[]; 51 | 52 | // Count of the cached data bytes about to be written 53 | private int dataBytes; 54 | 55 | // Size of the block header for this file 56 | private int blockHeaderSize; 57 | 58 | // Number of random bytes per block header 59 | private int blockMACRandLen; 60 | 61 | // Number of MAC bytes per block header 62 | private int blockMACLen; 63 | 64 | // Index of the current block to be written 65 | private int curBlockIndex; 66 | 67 | /** 68 | * Create a new EncFSOutputStream for writing encrypted data to a file on an 69 | * EncFS volume 70 | * 71 | * @param volume 72 | * Volume hosting the file to write 73 | * @param out 74 | * Output stream for writing the encrypted (raw) data 75 | * @param volumePath 76 | * Volume path of the file being encrypted (needed for 77 | * externalIVChaining) 78 | *

79 | *

80 | * File data is corrupt 81 | *

82 | * Unsupported EncFS configuration 83 | */ 84 | public EncFSOutputStream(EncFSVolume volume, OutputStream out, 85 | String volumePath) throws EncFSUnsupportedException, 86 | EncFSCorruptDataException { 87 | super(out); 88 | this.volume = volume; 89 | this.config = volume.getConfig(); 90 | int blockSize = config.getEncryptedFileBlockSizeInBytes(); 91 | this.blockHeaderSize = config.getNumberOfMACBytesForEachFileBlock() 92 | + config.getNumberOfRandomBytesInEachMACHeader(); 93 | this.dataBytes = this.blockHeaderSize; 94 | this.blockMACLen = config.getNumberOfMACBytesForEachFileBlock(); 95 | this.blockMACRandLen = config.getNumberOfRandomBytesInEachMACHeader(); 96 | 97 | if (config.isUseUniqueIV()) { 98 | // Compute file IV 99 | this.fileHeader = new byte[8]; 100 | 101 | secureRandom.nextBytes(fileHeader); 102 | 103 | byte[] initIv; 104 | if (config.isSupportedExternalIVChaining()) { 105 | /* 106 | * When using external IV chaining we compute initIv based on 107 | * the file path. 108 | */ 109 | initIv = StreamCrypto.computeChainIv(volume, volumePath); 110 | } else { 111 | // When not using external IV chaining initIv is just zero's. 112 | initIv = new byte[8]; 113 | } 114 | 115 | try { 116 | this.fileIv = StreamCrypto.streamDecrypt(volume, initIv, 117 | Arrays.copyOf(fileHeader, fileHeader.length)); 118 | } catch (InvalidAlgorithmParameterException e) { 119 | e.printStackTrace(); 120 | } catch (IllegalBlockSizeException e) { 121 | throw new EncFSCorruptDataException(e); 122 | } catch (BadPaddingException e) { 123 | throw new EncFSCorruptDataException(e); 124 | } 125 | } else { 126 | // No unique IV per file, just use 0 127 | this.fileIv = new byte[8]; 128 | } 129 | 130 | Cipher blockCipher = BlockCrypto.newBlockCipher(); 131 | try { 132 | EncFSCrypto.cipherInit(volume, Cipher.ENCRYPT_MODE, blockCipher, 133 | fileIv); 134 | } catch (InvalidAlgorithmParameterException e) { 135 | throw new EncFSCorruptDataException(e); 136 | } 137 | Cipher streamCipher = StreamCrypto.newStreamCipher(); 138 | try { 139 | EncFSCrypto.cipherInit(volume, Cipher.ENCRYPT_MODE, streamCipher, 140 | fileIv); 141 | } catch (InvalidAlgorithmParameterException e) { 142 | throw new EncFSCorruptDataException(e); 143 | } 144 | 145 | // blockSize = blockHeaderSize + blockDataLen 146 | dataBuf = new byte[blockSize]; 147 | } 148 | 149 | // Flush the internal buffer 150 | private void writeBuffer(boolean isFinal) throws IOException { 151 | 152 | if (!isFinal && dataBytes != dataBuf.length) { 153 | throw new IllegalStateException("Buffer not full"); 154 | } 155 | 156 | if (curBlockIndex == 0 && config.isUseUniqueIV()) { 157 | out.write(this.fileHeader); 158 | } 159 | 160 | // Fill in the block header 161 | if (blockHeaderSize > 0) { 162 | 163 | // Add random bytes to the buffer 164 | if (blockMACRandLen > 0) { 165 | byte randomBytes[] = new byte[blockMACRandLen]; 166 | secureRandom.nextBytes(randomBytes); 167 | System.arraycopy(randomBytes, 0, dataBuf, blockMACLen, 168 | blockMACRandLen); 169 | } 170 | 171 | // Compute MAC bytes and add them to the buffer 172 | byte mac[] = EncFSCrypto.mac64(volume.getMAC(), dataBuf, 173 | blockMACLen, dataBytes - blockMACLen); 174 | for (int i = 0; i < blockMACLen; i++) { 175 | dataBuf[i] = mac[7 - i]; 176 | } 177 | } 178 | 179 | byte[] encBuffer; 180 | try { 181 | if (dataBytes == dataBuf.length) { 182 | /* 183 | * If allowHoles is configured, we scan the buffer to determine 184 | * whether we should pass this block through as a zero block. 185 | * Note that it is intended for the presence of a MAC header to 186 | * cause this check to fail. 187 | */ 188 | boolean zeroBlock = false; 189 | if (config.isHolesAllowedInFiles()) { 190 | zeroBlock = true; 191 | for (byte aDataBuf : dataBuf) { 192 | if (aDataBuf != 0) { 193 | zeroBlock = false; 194 | break; 195 | } 196 | } 197 | } 198 | 199 | if (zeroBlock) { 200 | encBuffer = dataBuf; 201 | } else { 202 | encBuffer = BlockCrypto.blockEncrypt(volume, 203 | getBlockIV(), dataBuf); 204 | } 205 | } else { 206 | encBuffer = StreamCrypto.streamEncrypt(volume, 207 | getBlockIV(), dataBuf, 0, dataBytes); 208 | } 209 | } catch (IllegalBlockSizeException e) { 210 | throw new IOException(e); 211 | } catch (BadPaddingException e) { 212 | throw new IOException(e); 213 | } catch (InvalidAlgorithmParameterException e) { 214 | throw new IOException(e); 215 | } catch (EncFSUnsupportedException e) { 216 | throw new IOException(e); 217 | } 218 | 219 | out.write(encBuffer); 220 | dataBytes = blockHeaderSize; 221 | curBlockIndex++; 222 | } 223 | 224 | // Return the block IV for the current block 225 | private byte[] getBlockIV() { 226 | long fileIvLong = EncFSUtil.convertByteArrayToLong(fileIv); 227 | return EncFSUtil.convertLongToByteArrayBigEndian(curBlockIndex 228 | ^ fileIvLong); 229 | } 230 | 231 | // Flush the internal buffer 232 | private void writeBuffer() throws IOException { 233 | writeBuffer(false); 234 | } 235 | 236 | /* 237 | * (non-Javadoc) 238 | * 239 | * @see java.io.FilterOutputStream#write(int) 240 | */ 241 | @Override 242 | public synchronized void write(int b) throws IOException { 243 | dataBuf[dataBytes++] = (byte) b; 244 | 245 | if (dataBytes == dataBuf.length) { 246 | writeBuffer(); 247 | } 248 | } 249 | 250 | /* 251 | * (non-Javadoc) 252 | * 253 | * @see java.io.FilterOutputStream#write(int) 254 | */ 255 | @Override 256 | public synchronized void write(byte b[], int off, int len) 257 | throws IOException { 258 | if (dataBytes + len <= dataBuf.length) { 259 | System.arraycopy(b, off, dataBuf, dataBytes, len); 260 | dataBytes += len; 261 | 262 | if (dataBytes == dataBuf.length) { 263 | writeBuffer(); 264 | } 265 | } else { 266 | int tmpOff = off; 267 | int remaining = len; 268 | while (remaining > 0) { 269 | int chunk = Math.min(remaining, dataBuf.length - dataBytes); 270 | 271 | write(b, tmpOff, chunk); 272 | 273 | remaining -= chunk; 274 | tmpOff += chunk; 275 | } 276 | } 277 | } 278 | 279 | /* 280 | * (non-Javadoc) 281 | * 282 | * @see java.io.FilterOutputStream#write(int) 283 | */ 284 | @Override 285 | public void close() throws IOException { 286 | writeBuffer(true); 287 | super.close(); 288 | } 289 | } 290 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSPBKDF2Provider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | /** 19 | * Abstract class for providing a custom PBKDF2 implementation 20 | */ 21 | public abstract class EncFSPBKDF2Provider { 22 | 23 | /** 24 | * @param passwordLen 25 | * Length of the password provided in 'password' 26 | * @param password 27 | * Password to hash 28 | * @param saltLen 29 | * Length of the salt provided in 'salt' 30 | * @param salt 31 | * Salt data 32 | * @param iterations 33 | * Number of PBKDF2 iterations to perform 34 | * @param keyLen 35 | * Desired length of the resulting key material in bytes 36 | * @return Byte array containing the result of the PBKDF2 computation. null 37 | * if the computation failed. 38 | */ 39 | public abstract byte[] doPBKDF2(String password, int saltLen, byte[] salt, 40 | int iterations, int keyLen); 41 | 42 | } -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSProgressListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | /** 19 | * Class representing a progress listener for long running operations 20 | */ 21 | public abstract class EncFSProgressListener { 22 | 23 | /** 24 | * Event notifying that the number of affected files/directories have been 25 | * counted. 26 | */ 27 | public static final int FILES_COUNTED_EVENT = 0; 28 | 29 | /** 30 | * Event notifying that a new file has started to be processed 31 | */ 32 | public static final int NEW_FILE_EVENT = 1; 33 | 34 | /** 35 | * Event notifying that a single file or directory has been processed. 36 | */ 37 | public static final int FILE_PROCESS_EVENT = 2; 38 | 39 | /** 40 | * Event notifying completion of the whole operation. 41 | */ 42 | public static final int OP_COMPLETE_EVENT = 3; 43 | 44 | // Name of the current file being operated on 45 | private String currentFile = null; 46 | 47 | // Number of files being operated on 48 | private int numFiles = 0; 49 | 50 | /** 51 | * Method that must be overridden by extending class to handle events posted 52 | * to the event listener 53 | * 54 | * @param eventType 55 | * Type of the event that just occured 56 | */ 57 | public abstract void handleEvent(int eventType); 58 | 59 | /** 60 | * Get the name of the current file being operated on 61 | * 62 | * @return name of the current file being operated on 63 | */ 64 | public String getCurrentFile() { 65 | return currentFile; 66 | } 67 | 68 | /** 69 | * Get the total number of files that the operation will proceed on. Note 70 | * that this value is undefined until a FILES_COUNTED_EVENT is posted first 71 | * 72 | * @return total number of files that the operation will proceed on 73 | */ 74 | public int getNumFiles() { 75 | return numFiles; 76 | } 77 | 78 | // Post an event to the progress listener 79 | void postEvent(int eventType) { 80 | handleEvent(eventType); 81 | } 82 | 83 | // Set the current file 84 | void setCurrentFile(String fileName) { 85 | currentFile = fileName; 86 | postEvent(NEW_FILE_EVENT); 87 | } 88 | 89 | // Set the total number of files being operated on 90 | void setNumFiles(int numFiles) { 91 | this.numFiles = numFiles; 92 | postEvent(FILES_COUNTED_EVENT); 93 | } 94 | } -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSUnsupportedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | public class EncFSUnsupportedException extends EncFSException { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | public EncFSUnsupportedException(String message) { 23 | super(message); 24 | } 25 | 26 | public EncFSUnsupportedException(Throwable cause) { 27 | super(cause); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 Mark R. Pariente 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs; 17 | 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | import java.io.OutputStream; 21 | import java.nio.ByteBuffer; 22 | 23 | /** 24 | * Class containing static methods implementing misc. functionality for the rest 25 | * of the library 26 | */ 27 | public final class EncFSUtil { 28 | 29 | private static final int EIGHT = 8; 30 | private static final int EIGHT_KILO = 8192; 31 | 32 | EncFSUtil() { 33 | } 34 | 35 | /** 36 | * Convert the given byte array to 'int' 37 | * 38 | * @param b 39 | * A 4-byte array 40 | * 41 | * @return int value of the array contents 42 | */ 43 | public static int convertBigEndianByteArrayToInt(byte[] b) { 44 | int capacity = Integer.SIZE / EIGHT; 45 | if (b.length > capacity) { 46 | return -1; 47 | } 48 | return ByteBuffer.wrap(b).getInt(); 49 | } 50 | 51 | /** 52 | * Convert the given int to a 4-byte array 53 | * 54 | * @param i 55 | * An 'int' 56 | * 57 | * @return A 4-byte array in big endian (MSB) ordering 58 | */ 59 | public static byte[] convertIntToByteArrayBigEndian(int i) { 60 | return ByteBuffer.allocate(Integer.SIZE / EIGHT).putInt(i).array(); 61 | } 62 | 63 | /** 64 | * Convert the given byte array to 'long' 65 | * 66 | * @param b 67 | * An 8-byte array 68 | * @return long value of the array contents 69 | */ 70 | public static long convertByteArrayToLong(byte[] b) { 71 | int capacity = Long.SIZE / EIGHT; 72 | if (b.length > capacity) { 73 | return -1; 74 | } 75 | return ByteBuffer.wrap(b).getLong(); 76 | } 77 | 78 | /** 79 | * Convert the given long to an 8-byte array 80 | * 81 | * @param l 82 | * A 'long' 83 | * 84 | * @return An 8-byte array in big endian (MSB) ordering 85 | */ 86 | public static byte[] convertLongToByteArrayBigEndian(long l) { 87 | return ByteBuffer.allocate(Long.SIZE / EIGHT).putLong(l).array(); 88 | } 89 | 90 | /** 91 | * Copy the entire content of an InputStream into an OutputStream and close 92 | * only the input stream. 93 | * 94 | * @param in 95 | * The InputStream to read data from 96 | * @param out 97 | * The OutputStream to write data to 98 | * 99 | * @throws IOException 100 | * I/O exception from read or write 101 | */ 102 | public static void copyWholeStreamAndCloseInput(InputStream in, 103 | OutputStream out) throws IOException { 104 | try { 105 | readFromAndWriteTo(in, out); 106 | } finally { 107 | in.close(); 108 | } 109 | } 110 | 111 | /** 112 | * Copy the entire content of an InputStream into an OutputStream and close 113 | * both streams. 114 | * 115 | * @param in 116 | * The InputStream to read data from 117 | * @param out 118 | * The OutputStream to write data to 119 | * 120 | * @throws IOException 121 | * I/O exception from read or write 122 | */ 123 | public static void copyWholeStreamAndClose(InputStream in, OutputStream out) 124 | throws IOException { 125 | try { 126 | copyWholeStreamAndCloseInput(in, out); 127 | } finally { 128 | out.close(); 129 | } 130 | } 131 | 132 | private static void readFromAndWriteTo(InputStream in, OutputStream out) 133 | throws IOException { 134 | byte[] buf = new byte[EIGHT_KILO]; 135 | int bytesRead = in.read(buf); 136 | while (bytesRead >= 0) { 137 | out.write(buf, 0, bytesRead); 138 | bytesRead = in.read(buf); 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/EncFSVolumeBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | import java.io.File; 18 | import java.io.IOException; 19 | import java.security.SecureRandom; 20 | 21 | /** 22 | * Class for building EncFSVolume objects and writing new volume files to file 23 | * providers. 24 | * 25 | * Usage (in order): 26 | * 27 | * [Required] .withFileProvider(provider) OR .withRootPath(rootPath) 28 | * 29 | * [Optional] .withConfig(config) AND/OR .withPbkdfProvider(pbkdf2provider) 30 | * 31 | * [Required] .withPassword(password) 32 | * 33 | * 34 | * Volume building methods:
35 | * .writeVolumeConfig() - Write volume configuration file to the file provider
36 | * .buildVolume() - Return an EncFSVolume 37 | */ 38 | public final class EncFSVolumeBuilder { 39 | 40 | public static class FileProviderBuilder { 41 | 42 | private final EncFSVolume volume; 43 | 44 | public FileProviderBuilder(EncFSVolume volume, String rootPath) { 45 | this(volume, new EncFSLocalFileProvider(new File(rootPath))); 46 | } 47 | 48 | public FileProviderBuilder(EncFSVolume volume, 49 | EncFSFileProvider fileProvider) { 50 | this.volume = volume; 51 | volume.setFileProvider(fileProvider); 52 | } 53 | 54 | public ConfigBuilder withConfig(EncFSConfig config) { 55 | return new ConfigBuilder(volume, config); 56 | } 57 | 58 | public Pbkdf2ProviderBuilder withPbkdf2Provider( 59 | EncFSPBKDF2Provider pbkdf2Provider) 60 | throws EncFSUnsupportedException, IOException, 61 | EncFSInvalidConfigException { 62 | return new ConfigBuilder(volume).withPbkdf2Provider(pbkdf2Provider); 63 | } 64 | 65 | public PasswordBuilder withPassword(String password) 66 | throws EncFSUnsupportedException, IOException, 67 | EncFSInvalidConfigException, EncFSCorruptDataException, 68 | EncFSInvalidPasswordException { 69 | return withPbkdf2Provider(null).withPassword(password); 70 | } 71 | 72 | public PasswordBuilder withDerivedKeyData(byte[] derivedKeyData) 73 | throws EncFSUnsupportedException, IOException, 74 | EncFSInvalidConfigException, EncFSCorruptDataException, 75 | EncFSInvalidPasswordException { 76 | return withPbkdf2Provider(null).withDerivedKeyData(derivedKeyData); 77 | } 78 | } 79 | 80 | public static class ConfigBuilder { 81 | 82 | private final EncFSVolume volume; 83 | 84 | public ConfigBuilder(EncFSVolume volume, EncFSConfig config) { 85 | this.volume = volume; 86 | volume.setVolumeConfig(config); 87 | } 88 | 89 | public ConfigBuilder(EncFSVolume volume) 90 | throws EncFSUnsupportedException, IOException, 91 | EncFSInvalidConfigException { 92 | this.volume = volume; 93 | EncFSFileProvider fileProvider = volume.getFileProvider(); 94 | EncFSConfig volumeConfiguration = EncFSConfigParser.parseConfig( 95 | fileProvider, EncFSVolume.CONFIG_FILE_NAME); 96 | volume.setVolumeConfig(volumeConfiguration); 97 | } 98 | 99 | public Pbkdf2ProviderBuilder withPbkdf2Provider( 100 | EncFSPBKDF2Provider provider) { 101 | return new Pbkdf2ProviderBuilder(volume, provider); 102 | } 103 | 104 | public PasswordBuilder withPassword(String password) 105 | throws EncFSCorruptDataException, 106 | EncFSInvalidPasswordException, EncFSInvalidConfigException, 107 | EncFSUnsupportedException, IOException { 108 | return withPbkdf2Provider(null).withPassword(password); 109 | } 110 | 111 | public PasswordBuilder withDerivedKeyData(byte[] derivedKeyData) 112 | throws EncFSUnsupportedException, IOException, 113 | EncFSInvalidConfigException, EncFSCorruptDataException, 114 | EncFSInvalidPasswordException { 115 | return withPbkdf2Provider(null).withDerivedKeyData(derivedKeyData); 116 | } 117 | } 118 | 119 | public static class Pbkdf2ProviderBuilder { 120 | 121 | private final EncFSVolume volume; 122 | private final EncFSPBKDF2Provider provider; 123 | 124 | public Pbkdf2ProviderBuilder(EncFSVolume volume, 125 | EncFSPBKDF2Provider provider) { 126 | this.volume = volume; 127 | this.provider = provider; 128 | } 129 | 130 | public PasswordBuilder withPassword(String password) { 131 | return new PasswordBuilder(volume, password, provider); 132 | } 133 | 134 | public PasswordBuilder withDerivedKeyData(byte[] derivedKeyData) { 135 | return new PasswordBuilder(volume, derivedKeyData); 136 | } 137 | } 138 | 139 | public static class PasswordBuilder { 140 | 141 | private final EncFSVolume volume; 142 | private final EncFSPBKDF2Provider provider; 143 | private final String password; 144 | 145 | public PasswordBuilder(EncFSVolume volume, byte[] derivedPassword) { 146 | this.volume = volume; 147 | this.provider = null; 148 | this.password = null; 149 | volume.setDerivedKeyData(derivedPassword); 150 | 151 | } 152 | 153 | public PasswordBuilder(EncFSVolume volume, String password, 154 | EncFSPBKDF2Provider provider) { 155 | this.volume = volume; 156 | this.password = password; 157 | this.provider = provider; 158 | } 159 | 160 | /** 161 | * Creates a new object representing an existing EncFS volume 162 | * 163 | * @throws EncFSInvalidPasswordException 164 | * Given password is incorrect 165 | * @throws EncFSCorruptDataException 166 | * Corrupt data detected (checksum error) 167 | * @throws EncFSInvalidConfigException 168 | * Configuration file format not recognized 169 | * @throws EncFSUnsupportedException 170 | * Unsupported EncFS version or options 171 | * @throws IOException 172 | * File provider returned I/O error 173 | */ 174 | public EncFSVolume buildVolume() throws EncFSUnsupportedException, 175 | IOException, EncFSInvalidConfigException, 176 | EncFSInvalidPasswordException, EncFSCorruptDataException { 177 | EncFSConfig config = volume.getConfig(); 178 | if (password != null) { 179 | byte[] derivedKeyData = VolumeKey.deriveKeyDataFromPassword( 180 | config, password, provider); 181 | volume.setDerivedKeyData(derivedKeyData); 182 | } 183 | volume.readConfigAndInitVolume(); 184 | return volume; 185 | } 186 | 187 | /** 188 | * Writes EncFS volume configuration to the file provider 189 | * 190 | * @throws EncFSInvalidPasswordException 191 | * Given password is incorrect 192 | * @throws EncFSCorruptDataException 193 | * Corrupt data detected (checksum error) 194 | * @throws EncFSInvalidConfigException 195 | * Configuration file format not recognized 196 | * @throws EncFSUnsupportedException 197 | * Unsupported EncFS version or options 198 | * @throws IOException 199 | * File provider returned I/O error 200 | */ 201 | public void writeVolumeConfig() throws EncFSUnsupportedException, 202 | IOException, EncFSInvalidConfigException, 203 | EncFSCorruptDataException { 204 | EncFSConfig config = volume.getConfig(); 205 | EncFSFileProvider fileProvider = volume.getFileProvider(); 206 | 207 | // Create a random volume VolumeCryptKey + IV pair 208 | byte[] randVolKey = new byte[config.getVolumeKeySizeInBits() / 8 209 | + EncFSVolume.IV_LENGTH_IN_BYTES]; 210 | new SecureRandom().nextBytes(randVolKey); 211 | 212 | VolumeKey.encodeVolumeKey(config, password, randVolKey, provider); 213 | EncFSConfigWriter.writeConfig(fileProvider, config); 214 | } 215 | } 216 | 217 | public FileProviderBuilder withRootPath(String rootPath) { 218 | return new FileProviderBuilder(new EncFSVolume(), rootPath); 219 | } 220 | 221 | public FileProviderBuilder withFileProvider(EncFSFileProvider fileProvider) { 222 | return new FileProviderBuilder(new EncFSVolume(), fileProvider); 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/FilenameDecryptionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | // Common class for all filename decryption strategies 18 | abstract class FilenameDecryptionStrategy { 19 | 20 | private final EncFSVolume volume; 21 | private final String volumePath; 22 | private final EncFSFilenameEncryptionAlgorithm algorithm; 23 | 24 | String getVolumePath() { 25 | return volumePath; 26 | } 27 | 28 | EncFSVolume getVolume() { 29 | return volume; 30 | } 31 | 32 | FilenameDecryptionStrategy(EncFSVolume volume, String volumePath, 33 | EncFSFilenameEncryptionAlgorithm algorithm) { 34 | this.volume = volume; 35 | this.volumePath = volumePath; 36 | this.algorithm = algorithm; 37 | } 38 | 39 | // Decryption implementation to be provided by subclass 40 | protected abstract String decryptImpl(String fileName) 41 | throws EncFSCorruptDataException, EncFSChecksumException; 42 | 43 | // Decrypt the given filename 44 | public String decrypt(String filename) throws EncFSChecksumException, 45 | EncFSCorruptDataException { 46 | if (volume.getConfig().getFilenameAlgorithm() != algorithm) { 47 | throw new IllegalStateException( 48 | "only accessable when algorithm is " + algorithm); 49 | } 50 | 51 | return decryptImpl(filename); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/FilenameEncryptionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | // Common class for all filename encryption strategies 18 | abstract class FilenameEncryptionStrategy { 19 | 20 | private final EncFSVolume volume; 21 | private final String volumePath; 22 | private final EncFSFilenameEncryptionAlgorithm algorithm; 23 | 24 | String getVolumePath() { 25 | return volumePath; 26 | } 27 | 28 | EncFSVolume getVolume() { 29 | return volume; 30 | } 31 | 32 | FilenameEncryptionStrategy(EncFSVolume volume, String volumePath, 33 | EncFSFilenameEncryptionAlgorithm algorithm) { 34 | this.volume = volume; 35 | this.volumePath = volumePath; 36 | this.algorithm = algorithm; 37 | } 38 | 39 | // Encryption implementation to be provided by subclass 40 | protected abstract String encryptImpl(String fileName) 41 | throws EncFSCorruptDataException; 42 | 43 | // Encrypt the given filename 44 | public String encrypt(String filename) throws EncFSCorruptDataException { 45 | if (volume.getConfig().getFilenameAlgorithm() != algorithm) { 46 | throw new IllegalStateException( 47 | "only accessable when algorithm is " + algorithm); 48 | } 49 | 50 | return encryptImpl(filename); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/NullFilenameDecryptionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | // Class implementing the NULL decryption strategy 18 | public class NullFilenameDecryptionStrategy extends FilenameDecryptionStrategy { 19 | 20 | public NullFilenameDecryptionStrategy(EncFSVolume volume, String volumePath) { 21 | super(volume, volumePath, EncFSFilenameEncryptionAlgorithm.NULL); 22 | } 23 | 24 | @Override 25 | protected String decryptImpl(String fileName) 26 | throws EncFSCorruptDataException, EncFSChecksumException { 27 | EncFSFile rootDir = getVolume().getRootDir(); 28 | // Filter out config file 29 | if (getVolumePath().equals(rootDir.getPath()) 30 | && fileName.equals(EncFSVolume.CONFIG_FILE_NAME)) { 31 | return null; 32 | } 33 | return fileName; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/NullFilenameEncryptionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | // Class implementing the NULL encryption strategy 18 | public class NullFilenameEncryptionStrategy extends FilenameEncryptionStrategy { 19 | 20 | public NullFilenameEncryptionStrategy(EncFSVolume volume, String volumePath) { 21 | super(volume, volumePath, EncFSFilenameEncryptionAlgorithm.NULL); 22 | } 23 | 24 | @Override 25 | protected String encryptImpl(String fileName) { 26 | return fileName; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/StreamCrypto.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | import javax.crypto.BadPaddingException; 18 | import javax.crypto.Cipher; 19 | import javax.crypto.IllegalBlockSizeException; 20 | import javax.crypto.Mac; 21 | import java.security.InvalidAlgorithmParameterException; 22 | import java.security.Key; 23 | import java.util.Arrays; 24 | import java.util.StringTokenizer; 25 | 26 | // Static methods for stream cryptography 27 | public class StreamCrypto { 28 | 29 | // Returns a stream cipher 30 | public static Cipher newStreamCipher() throws EncFSUnsupportedException { 31 | return EncFSCrypto.getCipher(EncFSCrypto.STREAM_CIPHER); 32 | } 33 | 34 | // Stream decryption implementation 35 | private static byte[] streamDecrypt(Cipher cipher, Mac mac, Key key, 36 | byte[] iv, byte[] ivSeed, byte[] data, int offset, int len) 37 | throws EncFSUnsupportedException, 38 | InvalidAlgorithmParameterException, IllegalBlockSizeException, 39 | BadPaddingException { 40 | // First round uses IV seed + 1 for IV generation 41 | byte[] ivSeedPlusOne = EncFSCrypto.incrementIvSeedByOne(ivSeed); 42 | 43 | EncFSCrypto.cipherInit(key, mac, Cipher.DECRYPT_MODE, cipher, iv, 44 | ivSeedPlusOne); 45 | byte[] firstDecResult = cipher.doFinal(data, offset, len); 46 | 47 | EncFSCrypto.unshuffleBytes(firstDecResult); 48 | 49 | byte[] flipBytesResult = EncFSCrypto.flipBytes(firstDecResult); 50 | 51 | // Second round of decryption with IV seed itself used for IV generation 52 | EncFSCrypto.cipherInit(key, mac, Cipher.DECRYPT_MODE, cipher, iv, 53 | ivSeed); 54 | byte[] result = cipher.doFinal(flipBytesResult); 55 | 56 | EncFSCrypto.unshuffleBytes(result); 57 | 58 | return result; 59 | } 60 | 61 | // Stream decryption implementation 62 | static byte[] streamDecrypt(Cipher cipher, Mac mac, Key key, byte[] iv, 63 | byte[] ivSeed, byte[] data) throws EncFSUnsupportedException, 64 | InvalidAlgorithmParameterException, IllegalBlockSizeException, 65 | BadPaddingException { 66 | return streamDecrypt(cipher, mac, key, iv, ivSeed, data, 0, data.length); 67 | } 68 | 69 | // Stream decryption implementation 70 | public static byte[] streamDecrypt(EncFSVolume volume, byte[] ivSeed, 71 | byte[] data) throws EncFSUnsupportedException, 72 | InvalidAlgorithmParameterException, IllegalBlockSizeException, 73 | BadPaddingException { 74 | Cipher streamCipher = volume.getStreamCipher(); 75 | return streamDecrypt(streamCipher, volume.getMAC(), volume.getKey(), 76 | volume.getIV(), ivSeed, data); 77 | } 78 | 79 | // Stream decryption implementation 80 | public static byte[] streamDecrypt(EncFSVolume volume, byte[] ivSeed, 81 | byte[] data, int offset, int len) throws EncFSUnsupportedException, 82 | InvalidAlgorithmParameterException, IllegalBlockSizeException, 83 | BadPaddingException { 84 | return streamDecrypt(volume.getStreamCipher(), volume.getMAC(), 85 | volume.getKey(), volume.getIV(), ivSeed, data, offset, len); 86 | } 87 | 88 | // Stream encryption implementation 89 | private static byte[] streamEncrypt(Cipher cipher, Mac mac, Key key, 90 | byte[] iv, byte[] ivSeed, byte[] data, int offset, int len) 91 | throws EncFSUnsupportedException, 92 | InvalidAlgorithmParameterException, IllegalBlockSizeException, 93 | BadPaddingException { 94 | // First round uses IV seed + 1 for IV generation 95 | byte[] ivSeedPlusOne = EncFSCrypto.incrementIvSeedByOne(ivSeed); 96 | 97 | byte[] encBuf = Arrays.copyOfRange(data, offset, offset + len); 98 | EncFSCrypto.shuffleBytes(encBuf); 99 | 100 | EncFSCrypto.cipherInit(key, mac, Cipher.ENCRYPT_MODE, cipher, iv, 101 | ivSeed); 102 | byte[] firstEncResult = cipher.doFinal(encBuf); 103 | 104 | byte[] flipBytesResult = EncFSCrypto.flipBytes(firstEncResult); 105 | 106 | EncFSCrypto.shuffleBytes(flipBytesResult); 107 | 108 | // Second round of encryption with IV seed itself used for IV generation 109 | EncFSCrypto.cipherInit(key, mac, Cipher.ENCRYPT_MODE, cipher, iv, 110 | ivSeedPlusOne); 111 | 112 | return cipher.doFinal(flipBytesResult); 113 | } 114 | 115 | // Stream encryption implementation 116 | static byte[] streamEncrypt(Cipher cipher, Mac mac, Key key, byte[] iv, 117 | byte[] ivSeed, byte[] data) throws EncFSUnsupportedException, 118 | InvalidAlgorithmParameterException, IllegalBlockSizeException, 119 | BadPaddingException { 120 | return streamEncrypt(cipher, mac, key, iv, ivSeed, data, 0, data.length); 121 | } 122 | 123 | // Stream encryption implementation 124 | public static byte[] streamEncrypt(EncFSVolume volume, byte[] ivSeed, 125 | byte[] data) throws EncFSUnsupportedException, 126 | InvalidAlgorithmParameterException, IllegalBlockSizeException, 127 | BadPaddingException { 128 | return streamEncrypt(volume.getStreamCipher(), volume.getMAC(), 129 | volume.getKey(), volume.getIV(), ivSeed, data); 130 | } 131 | 132 | // Stream encryption implementation 133 | public static byte[] streamEncrypt(EncFSVolume volume, byte[] ivSeed, 134 | byte[] data, int offset, int len) throws EncFSUnsupportedException, 135 | InvalidAlgorithmParameterException, IllegalBlockSizeException, 136 | BadPaddingException { 137 | return streamEncrypt(volume.getStreamCipher(), volume.getMAC(), 138 | volume.getKey(), volume.getIV(), ivSeed, data, offset, len); 139 | } 140 | 141 | /** 142 | * Compute chain IV for the given volume path 143 | * 144 | * @param volume 145 | * Volume to compute chain IV for 146 | * @param volumePath 147 | * Volume path to compute chain IV for 148 | * @return Computed chain IV 149 | */ 150 | public static byte[] computeChainIv(EncFSVolume volume, String volumePath) { 151 | byte[] chainIv = new byte[8]; 152 | StringTokenizer st = new StringTokenizer(volumePath, 153 | EncFSVolume.PATH_SEPARATOR); 154 | while (st.hasMoreTokens()) { 155 | String curPath = st.nextToken(); 156 | if ((curPath.length() > 0) 157 | && (!curPath.equals(EncFSVolume.PATH_SEPARATOR))) { 158 | byte[] encodeBytes; 159 | if (volume.getConfig().getFilenameAlgorithm() == EncFSFilenameEncryptionAlgorithm.BLOCK) { 160 | encodeBytes = EncFSCrypto 161 | .getBytesForBlockAlgorithm(curPath); 162 | } else { 163 | encodeBytes = curPath.getBytes(); 164 | } 165 | 166 | // Update chain IV 167 | EncFSCrypto.mac64(volume.getMAC(), encodeBytes, chainIv); 168 | } 169 | } 170 | 171 | return chainIv; 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/StreamFilenameDecryptionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | import javax.crypto.BadPaddingException; 18 | import javax.crypto.IllegalBlockSizeException; 19 | import java.security.InvalidAlgorithmParameterException; 20 | 21 | // Class implementing stream filename decryption strategy 22 | public class StreamFilenameDecryptionStrategy extends 23 | BasicFilenameDecryptionStrategy { 24 | 25 | public StreamFilenameDecryptionStrategy(EncFSVolume volume, 26 | String volumePath) { 27 | super(volume, volumePath, EncFSFilenameEncryptionAlgorithm.STREAM); 28 | } 29 | 30 | // Stream decryption 31 | protected byte[] decryptConcrete(EncFSVolume volume, byte[] encFileName, 32 | byte[] fileIv) throws EncFSCorruptDataException { 33 | try { 34 | return StreamCrypto.streamDecrypt(volume, fileIv, encFileName); 35 | } catch (InvalidAlgorithmParameterException e) { 36 | throw new EncFSCorruptDataException(e); 37 | } catch (IllegalBlockSizeException e) { 38 | throw new EncFSCorruptDataException(e); 39 | } catch (BadPaddingException e) { 40 | throw new EncFSCorruptDataException(e); 41 | } catch (EncFSUnsupportedException e) { 42 | throw new EncFSCorruptDataException(e); 43 | } 44 | } 45 | 46 | public String decryptPost(byte[] fileName) { 47 | return new String(fileName); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/StreamFilenameEncryptionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | import javax.crypto.BadPaddingException; 18 | import javax.crypto.IllegalBlockSizeException; 19 | import java.security.InvalidAlgorithmParameterException; 20 | 21 | //Implementation of block filename decryption strategy 22 | public class StreamFilenameEncryptionStrategy extends 23 | BasicFilenameEncryptionStrategy { 24 | 25 | public StreamFilenameEncryptionStrategy(EncFSVolume volume, 26 | String volumePath) { 27 | super(volume, volumePath, EncFSFilenameEncryptionAlgorithm.STREAM); 28 | } 29 | 30 | // Stream encryption 31 | @Override 32 | protected byte[] encryptConcrete(EncFSVolume volume, 33 | byte[] paddedDecFileName, byte[] fileIv) 34 | throws EncFSCorruptDataException { 35 | try { 36 | return StreamCrypto.streamEncrypt(volume, fileIv, 37 | paddedDecFileName); 38 | } catch (InvalidAlgorithmParameterException e) { 39 | throw new EncFSCorruptDataException(e); 40 | } catch (IllegalBlockSizeException e) { 41 | throw new EncFSCorruptDataException(e); 42 | } catch (BadPaddingException e) { 43 | throw new EncFSCorruptDataException(e); 44 | } catch (EncFSUnsupportedException e) { 45 | throw new EncFSCorruptDataException(e); 46 | } 47 | } 48 | 49 | protected byte[] getPaddedDecFilename(byte[] decFileName) { 50 | return decFileName; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/mrpdaemon/sec/encfs/VolumeKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs; 16 | 17 | import javax.crypto.*; 18 | import javax.crypto.spec.PBEKeySpec; 19 | import java.io.IOException; 20 | import java.security.*; 21 | import java.security.spec.InvalidKeySpecException; 22 | import java.security.spec.KeySpec; 23 | import java.util.Arrays; 24 | 25 | // Class containing static methods implementing volume key functionality 26 | class VolumeKey { 27 | 28 | // Derive volume key for the given config and password-based key/IV data 29 | private static byte[] encryptVolumeKey(EncFSConfig config, 30 | byte[] pbkdf2Data, byte[] volKeyData) 31 | throws EncFSUnsupportedException, EncFSInvalidConfigException, 32 | EncFSCorruptDataException { 33 | // Prepare key/IV for decryption 34 | int keySizeInBytes = config.getVolumeKeySizeInBits() / 8; 35 | byte[] passKeyData = Arrays.copyOfRange(pbkdf2Data, 0, keySizeInBytes); 36 | byte[] passIvData = Arrays.copyOfRange(pbkdf2Data, keySizeInBytes, 37 | keySizeInBytes + EncFSVolume.IV_LENGTH_IN_BYTES); 38 | 39 | Key passKey = EncFSCrypto.newKey(passKeyData); 40 | 41 | // Encrypt the volume key data 42 | Mac mac = encryptVolumeKeyData(passKey); 43 | 44 | // Calculate MAC for the key 45 | byte[] mac32 = EncFSCrypto.mac32(mac, volKeyData, new byte[0]); 46 | byte[] cipherVolKeyData = EncFSCrypto.encryptKeyData(volKeyData, 47 | passIvData, passKey, mac, mac32); 48 | 49 | // Combine MAC with key data 50 | byte[] result = new byte[mac32.length + cipherVolKeyData.length]; 51 | 52 | System.arraycopy(mac32, 0, result, 0, mac32.length); 53 | System.arraycopy(cipherVolKeyData, 0, result, mac32.length, 54 | cipherVolKeyData.length); 55 | 56 | return result; 57 | } 58 | 59 | private static Mac encryptVolumeKeyData(Key passKey) 60 | throws EncFSUnsupportedException, EncFSInvalidConfigException { 61 | Mac mac; 62 | try { 63 | mac = EncFSCrypto.newMac(passKey); 64 | } catch (InvalidKeyException e) { 65 | throw new EncFSInvalidConfigException(e); 66 | } 67 | return mac; 68 | } 69 | 70 | // Derive volume key for the given config and password-based key/IV data 71 | protected static byte[] decryptVolumeKey(EncFSConfig config, 72 | byte[] pbkdf2Data) throws EncFSChecksumException, 73 | EncFSInvalidConfigException, EncFSCorruptDataException, 74 | EncFSUnsupportedException { 75 | // Decode Base64 encoded ciphertext data 76 | // TODO: validate key/IV lengths 77 | byte[] cipherVolKeyData; 78 | try { 79 | cipherVolKeyData = EncFSBase64.decode(config 80 | .getBase64EncodedVolumeKey()); 81 | } catch (IOException e) { 82 | throw new EncFSInvalidConfigException("Corrupt key data in config"); 83 | } 84 | 85 | byte[] encryptedVolKey = Arrays.copyOfRange(cipherVolKeyData, 4, 86 | cipherVolKeyData.length); 87 | 88 | // Prepare key/IV for decryption 89 | int keySizeInBytes = config.getVolumeKeySizeInBits() / 8; 90 | byte[] passKeyData = Arrays.copyOfRange(pbkdf2Data, 0, keySizeInBytes); 91 | byte[] passIvData = Arrays.copyOfRange(pbkdf2Data, keySizeInBytes, 92 | keySizeInBytes + EncFSVolume.IV_LENGTH_IN_BYTES); 93 | 94 | Key passKey = EncFSCrypto.newKey(passKeyData); 95 | byte[] ivSeed = Arrays.copyOfRange(cipherVolKeyData, 0, 4); 96 | 97 | // Decrypt the volume key data 98 | Mac mac = encryptVolumeKeyData(passKey); 99 | byte[] clearVolKeyData = decryptVolumeKeyData(encryptedVolKey, 100 | passIvData, passKey, ivSeed, mac); 101 | 102 | // Perform checksum computation 103 | byte[] mac32 = EncFSCrypto.mac32(mac, clearVolKeyData, new byte[0]); 104 | 105 | if (!Arrays.equals(ivSeed, mac32)) { 106 | throw new EncFSChecksumException("Volume key checksum mismatch"); 107 | } 108 | 109 | return clearVolKeyData; 110 | } 111 | 112 | // Decrypt volume key data 113 | private static byte[] decryptVolumeKeyData(byte[] encryptedVolKey, 114 | byte[] passIvData, Key passKey, byte[] ivSeed, Mac mac) 115 | throws EncFSUnsupportedException, EncFSInvalidConfigException, 116 | EncFSCorruptDataException { 117 | byte[] clearVolKeyData; 118 | try { 119 | clearVolKeyData = StreamCrypto.streamDecrypt( 120 | StreamCrypto.newStreamCipher(), mac, passKey, passIvData, 121 | ivSeed, encryptedVolKey); 122 | } catch (InvalidAlgorithmParameterException e) { 123 | throw new EncFSInvalidConfigException(e); 124 | } catch (IllegalBlockSizeException e) { 125 | throw new EncFSCorruptDataException(e); 126 | } catch (BadPaddingException e) { 127 | throw new EncFSCorruptDataException(e); 128 | } 129 | return clearVolKeyData; 130 | } 131 | 132 | // Derive password-based key from input/config parameters using PBKDF2 133 | protected static byte[] deriveKeyDataFromPassword(EncFSConfig config, 134 | String password, EncFSPBKDF2Provider pbkdf2Provider) 135 | throws EncFSInvalidConfigException, EncFSUnsupportedException { 136 | // Decode base 64 salt data 137 | byte[] cipherSaltData; 138 | try { 139 | cipherSaltData = EncFSBase64.decode(config.getBase64Salt()); 140 | } catch (IOException e) { 141 | throw new EncFSInvalidConfigException("Corrupt salt data in config"); 142 | } 143 | 144 | if (pbkdf2Provider == null) { 145 | // Execute PBKDF2 to derive key data from the password 146 | SecretKeyFactory f; 147 | try { 148 | f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 149 | } catch (NoSuchAlgorithmException e) { 150 | throw new EncFSUnsupportedException(e); 151 | } 152 | KeySpec ks = new PBEKeySpec(password.toCharArray(), cipherSaltData, 153 | config.getIterationForPasswordKeyDerivationCount(), 154 | config.getVolumeKeySizeInBits() 155 | + EncFSVolume.IV_LENGTH_IN_BYTES * 8); 156 | SecretKey pbkdf2Key; 157 | try { 158 | pbkdf2Key = f.generateSecret(ks); 159 | } catch (InvalidKeySpecException e) { 160 | throw new EncFSInvalidConfigException(e); 161 | } 162 | 163 | return pbkdf2Key.getEncoded(); 164 | } else { 165 | return pbkdf2Provider.doPBKDF2(password, cipherSaltData.length, 166 | cipherSaltData, 167 | config.getIterationForPasswordKeyDerivationCount(), 168 | (config.getVolumeKeySizeInBits() / 8) 169 | + EncFSVolume.IV_LENGTH_IN_BYTES); 170 | } 171 | } 172 | 173 | // Encodes the given volume key using the supplied password parameters 174 | protected static void encodeVolumeKey(EncFSConfig config, String password, 175 | byte[] volKey, EncFSPBKDF2Provider pbkdf2Provider) 176 | throws EncFSInvalidConfigException, EncFSUnsupportedException, 177 | EncFSCorruptDataException { 178 | SecureRandom random = new SecureRandom(); 179 | config.setSaltLengthBytes(20); 180 | 181 | // Generate random salt 182 | byte[] salt = new byte[20]; 183 | random.nextBytes(salt); 184 | config.setBase64Salt(EncFSBase64.encodeBytes(salt)); 185 | 186 | // Get password key data 187 | byte[] pbkdf2Data = deriveKeyDataFromPassword(config, password, 188 | pbkdf2Provider); 189 | 190 | // Encode volume key 191 | byte[] encodedVolKey = encryptVolumeKey(config, pbkdf2Data, volKey); 192 | 193 | config.setEncodedKeyLengthInBytes(encodedVolKey.length); 194 | config.setBase64EncodedVolumeKey(EncFSBase64.encodeBytes(encodedVolKey)); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/main/resources/org/mrpdaemon/sec/encfs/library.properties: -------------------------------------------------------------------------------- 1 | library.version=${pom.version} 2 | -------------------------------------------------------------------------------- /src/test/java/org/mrpdaemon/sec/encfs/tests/EncFSBase64Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs.tests; 17 | 18 | import org.junit.Assert; 19 | import org.junit.Test; 20 | import org.mrpdaemon.sec.encfs.*; 21 | 22 | import javax.crypto.BadPaddingException; 23 | import javax.crypto.IllegalBlockSizeException; 24 | import java.io.IOException; 25 | import java.security.InvalidAlgorithmParameterException; 26 | 27 | public class EncFSBase64Test { 28 | 29 | @Test 30 | public void testDecodeEncodeEncfs() throws EncFSInvalidPasswordException, 31 | EncFSInvalidConfigException, EncFSCorruptDataException, 32 | EncFSUnsupportedException, EncFSChecksumException, IOException, 33 | InvalidAlgorithmParameterException, IllegalBlockSizeException, 34 | BadPaddingException { 35 | 36 | byte[] in = new byte[] { 87, 51, 103, 76, 111, 85, 113, 76, 45, 48, 89, 37 | 122, 85, 104, 56, 117, 100, 80, 56 }; 38 | byte[] out = new byte[] { 98, -63, 94, 52, 104, 95, -127, 64, -2, 96, 39 | -85, -24, -23, -90 }; 40 | 41 | byte[] out1 = EncFSBase64.decodeEncfs(in); 42 | Assert.assertArrayEquals(out, out1); 43 | 44 | byte[] in1 = EncFSBase64.encodeEncfs(out); 45 | 46 | Assert.assertArrayEquals(in, in1); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/org/mrpdaemon/sec/encfs/tests/EncFSComparer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs.tests; 17 | 18 | import org.mrpdaemon.sec.encfs.*; 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import java.io.*; 23 | import java.util.Arrays; 24 | import java.util.Comparator; 25 | 26 | /** 27 | * Simple tool that takes a raw encfs volume (& uses encfs-java to unencrypt it) 28 | * and compares it to a the same mounted encfs volume to check they are the 29 | * same. 30 | */ 31 | public class EncFSComparer { 32 | private static final Logger logger = LoggerFactory 33 | .getLogger(EncFSComparer.class); 34 | 35 | public static void main(String[] args) throws Exception { 36 | if (args == null || args.length != 3) 37 | throw new IllegalArgumentException("Missing required args"); 38 | 39 | File rawEncFSVolume = new File(args[0]); 40 | String password = args[1]; 41 | File decodedEncFSOutput = new File(args[2]); 42 | 43 | EncFSComparer encFSComparer = new EncFSComparer(rawEncFSVolume, 44 | password, decodedEncFSOutput); 45 | int result = encFSComparer.compare(); 46 | System.exit(result); 47 | } 48 | 49 | private final File rawEncFSVolume; 50 | private final String password; 51 | private final File decodedEncFSOutput; 52 | 53 | private EncFSComparer(File rawEncFSVolume, String password, 54 | File decodedEncFSOutput) { 55 | this.rawEncFSVolume = rawEncFSVolume; 56 | this.password = password; 57 | this.decodedEncFSOutput = decodedEncFSOutput; 58 | } 59 | 60 | private int compare() throws EncFSInvalidPasswordException, 61 | EncFSInvalidConfigException, EncFSCorruptDataException, 62 | EncFSUnsupportedException, EncFSChecksumException, IOException { 63 | logger.info( 64 | "Performing compare between encfs raw volume at {} and output files at {}", 65 | rawEncFSVolume, decodedEncFSOutput); 66 | 67 | EncFSVolume volume = new EncFSVolumeBuilder() 68 | .withRootPath(rawEncFSVolume.getAbsolutePath()) 69 | .withPassword(password).buildVolume(); 70 | EncFSFile rootDir = volume.getRootDir(); 71 | int result = compare(rootDir, decodedEncFSOutput); 72 | 73 | if (result == 0) { 74 | logger.info("All files / folders match"); 75 | } else { 76 | logger.info("Errors between files / folders found"); 77 | } 78 | 79 | return result; 80 | } 81 | 82 | private int compare(EncFSFile encFsDir, File decodedFsDir) 83 | throws EncFSUnsupportedException, IOException, 84 | EncFSCorruptDataException { 85 | logger.info("Comparing directory {}", decodedFsDir.getAbsoluteFile()); 86 | 87 | EncFSFile[] encFsFiles = encFsDir.listFiles(); 88 | File[] decodedFsFiles = decodedFsDir.listFiles(); 89 | 90 | Arrays.sort(encFsFiles, SimpleEncFSFileComparator.getInstance()); 91 | Arrays.sort(decodedFsFiles, SimpleFileComparator.getInstance()); 92 | 93 | if (encFsFiles.length != decodedFsFiles.length) { 94 | logger.error("File count miss match in directory {}", 95 | decodedFsDir.getAbsoluteFile()); 96 | return -1; 97 | } else { 98 | for (int i = 0; i < encFsFiles.length; i++) { 99 | EncFSFile encFsFile = encFsFiles[i]; 100 | File decodedFsFile = decodedFsFiles[i]; 101 | 102 | if (!encFsFile.getName().equals(decodedFsFile.getName())) { 103 | logger.error("File name miss match ({}, {}, {})", 104 | new Object[] { i, encFsFile.getName(), 105 | decodedFsFile.getName() }); 106 | return -1; 107 | } 108 | 109 | String reEncEncfsName = EncFSCrypto.encodeName( 110 | encFsFile.getVolume(), encFsFile.getName(), 111 | encFsFile.getParentPath()); 112 | String rawFileName = encFsFile.getEncrytedName(); 113 | if (!rawFileName.equals(reEncEncfsName)) { 114 | logger.error("Re-encoded name miss match ({}, {}, {}, {})", 115 | new Object[] { i, encFsFile.getName(), rawFileName, 116 | reEncEncfsName }); 117 | return -1; 118 | } 119 | 120 | if (encFsFile.getLastModified() != decodedFsFile.lastModified()) { 121 | logger.error("File {} lastModified miss match", 122 | decodedFsFile.getName()); 123 | return -1; 124 | } 125 | 126 | if (encFsFile.getLength() != decodedFsFile.length()) { 127 | logger.error( 128 | "File {} size miss match ({}, {})", 129 | new Object[] { decodedFsFile.getName(), 130 | encFsFile.getLength(), 131 | decodedFsFile.length() }); 132 | return -1; 133 | } 134 | 135 | if (decodedFsFile.isDirectory()) { 136 | int subResult = compare(encFsFile, decodedFsFile); 137 | if (subResult != 0) { 138 | return subResult; 139 | } 140 | } else { 141 | // Check that the EncFSFileInputStream reads the file the 142 | // same as 143 | // reading the file directly from the mounted encfs volume 144 | 145 | EncFSFileInputStream encfsIs = new EncFSFileInputStream( 146 | encFsFile); 147 | try { 148 | BufferedInputStream decFsIs = new BufferedInputStream( 149 | new FileInputStream(decodedFsFile)); 150 | String decodedFsFileName = decodedFsFile 151 | .getAbsoluteFile().getName(); 152 | try { 153 | int streamresult = compareInputStreams(encfsIs, 154 | decFsIs, decodedFsFileName); 155 | if (streamresult != 0) { 156 | return streamresult; 157 | } 158 | } finally { 159 | decFsIs.close(); 160 | } 161 | } finally { 162 | encfsIs.close(); 163 | } 164 | 165 | // Copy the file via input/output streams & then check that 166 | // the file is the same 167 | File t = File.createTempFile(this.getClass().getName(), 168 | ".tmp"); 169 | try { 170 | EncFSUtil.copyWholeStreamAndClose( 171 | new EncFSFileInputStream(encFsFile), 172 | new EncFSOutputStream(encFsDir.getVolume(), 173 | new BufferedOutputStream( 174 | new FileOutputStream(t)), 175 | encFsFile.getPath())); 176 | 177 | FileInputStream reEncFSIs = new FileInputStream(t); 178 | try { 179 | InputStream origEncFSIs = encFsFile 180 | .getVolume() 181 | .getFileProvider() 182 | .openInputStream( 183 | encFsFile.getEncryptedPath()); 184 | try { 185 | int streamresult = compareInputStreams( 186 | origEncFSIs, reEncFSIs, 187 | encFsFile.getPath()); 188 | if (streamresult != 0) { 189 | return streamresult; 190 | } 191 | } finally { 192 | origEncFSIs.close(); 193 | } 194 | } finally { 195 | reEncFSIs.close(); 196 | } 197 | 198 | } finally { 199 | if (t.exists()) { 200 | t.delete(); 201 | } 202 | } 203 | } 204 | } 205 | } 206 | 207 | return 0; 208 | } 209 | 210 | private int compareInputStreams(InputStream encfsIs, InputStream decFsIs, 211 | String decodedFsFileName) throws IOException { 212 | int bytesRead = 0; 213 | int bytesRead2; 214 | while (bytesRead >= 0) { 215 | byte[] readBuf = new byte[128]; 216 | byte[] readBuf2 = new byte[128]; 217 | 218 | bytesRead = encfsIs.read(readBuf); 219 | bytesRead2 = decFsIs.read(readBuf2); 220 | 221 | if (bytesRead != bytesRead2) { 222 | logger.error( 223 | "File bytes read missmatch {} ({}, {})", 224 | new Object[] { decodedFsFileName, bytesRead, bytesRead2 }); 225 | return -1; 226 | } 227 | 228 | if (!Arrays.equals(readBuf, readBuf2)) { 229 | logger.error("File bytes missmatch {}", decodedFsFileName); 230 | return -1; 231 | } 232 | } 233 | return 0; 234 | } 235 | 236 | private static class SimpleEncFSFileComparator implements 237 | Comparator { 238 | private static final SimpleEncFSFileComparator instance = new SimpleEncFSFileComparator(); 239 | 240 | public static SimpleEncFSFileComparator getInstance() { 241 | return instance; 242 | } 243 | 244 | public int compare(EncFSFile arg0, EncFSFile arg1) { 245 | if (arg0.isDirectory() != arg1.isDirectory()) { 246 | if (arg0.isDirectory()) { 247 | return -1; 248 | } else { 249 | return 1; 250 | } 251 | } else { 252 | return arg0.getName().compareTo(arg1.getName()); 253 | } 254 | } 255 | } 256 | 257 | private static class SimpleFileComparator implements Comparator { 258 | private static final SimpleFileComparator instance = new SimpleFileComparator(); 259 | 260 | public static SimpleFileComparator getInstance() { 261 | return instance; 262 | } 263 | 264 | public int compare(File arg0, File arg1) { 265 | if (arg0.isDirectory() != arg1.isDirectory()) { 266 | if (arg0.isDirectory()) { 267 | return -1; 268 | } else { 269 | return 1; 270 | } 271 | } else { 272 | return arg0.getName().compareTo(arg1.getName()); 273 | } 274 | } 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /src/test/java/org/mrpdaemon/sec/encfs/tests/EncFSCryptoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs.tests; 17 | 18 | import org.junit.Assert; 19 | import org.junit.Test; 20 | import org.mrpdaemon.sec.encfs.EncFSVolume; 21 | import org.mrpdaemon.sec.encfs.EncFSVolumeBuilder; 22 | import org.mrpdaemon.sec.encfs.StreamCrypto; 23 | 24 | import java.io.File; 25 | import java.util.Arrays; 26 | 27 | public class EncFSCryptoTest { 28 | private final static String password = "test"; 29 | private final static String pathname = "test/encfs_samples/boxcryptor_1"; 30 | 31 | @Test 32 | public void testStreamEncodeDecode() throws Exception { 33 | EncFSVolume volume = getEncFSVolume(); 34 | byte[] orig = new byte[] { 116, 101, 115, 116, 102, 105, 108, 101, 46, 35 | 116, 120, 116 }; 36 | byte[] ivSeed = new byte[] { 0, 0, 0, 0, 0, 0, 98, -63 }; 37 | 38 | byte[] b1 = StreamCrypto.streamEncrypt(volume, ivSeed, 39 | Arrays.copyOf(orig, orig.length)); 40 | byte[] b2 = StreamCrypto.streamDecrypt(volume, ivSeed, 41 | Arrays.copyOf(b1, b1.length)); 42 | 43 | Assert.assertArrayEquals(orig, b2); 44 | } 45 | 46 | @Test 47 | public void testStreamEncodeDecode2() throws Exception { 48 | EncFSVolume volume = getEncFSVolume(); 49 | byte[] orig = "test file\r".getBytes(); 50 | byte[] ivSeed = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; 51 | 52 | byte[] b1 = StreamCrypto.streamEncrypt(volume, ivSeed, 53 | Arrays.copyOf(orig, orig.length)); 54 | byte[] b2 = StreamCrypto.streamDecrypt(volume, ivSeed, 55 | Arrays.copyOf(b1, b1.length)); 56 | 57 | Assert.assertArrayEquals(orig, b2); 58 | } 59 | 60 | private static EncFSVolume getEncFSVolume() throws Exception { 61 | File encFSDir = assertExistingPath(EncFSCryptoTest.pathname); 62 | return new EncFSVolumeBuilder() 63 | .withRootPath(encFSDir.getAbsolutePath()) 64 | .withPassword(EncFSCryptoTest.password).buildVolume(); 65 | } 66 | 67 | private static File assertExistingPath(String pathname) { 68 | File encFSDir = new File(pathname); 69 | Assert.assertTrue(encFSDir.exists()); 70 | return encFSDir; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/org/mrpdaemon/sec/encfs/tests/EncFSFilenameEncryptionAlgorithmTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2013 encfs-java authors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | package org.mrpdaemon.sec.encfs.tests; 16 | 17 | import org.junit.Test; 18 | 19 | import org.mrpdaemon.sec.encfs.EncFSFilenameEncryptionAlgorithm; 20 | 21 | public class EncFSFilenameEncryptionAlgorithmTest { 22 | @Test(expected = IllegalArgumentException.class) 23 | public void testParse() throws Exception { 24 | EncFSFilenameEncryptionAlgorithm.parse("nameio/sstream"); 25 | } 26 | } -------------------------------------------------------------------------------- /src/test/java/org/mrpdaemon/sec/encfs/tests/EncFSUtilTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EncFS Java Library 3 | * Copyright (C) 2011 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package org.mrpdaemon.sec.encfs.tests; 17 | 18 | import org.junit.Assert; 19 | import org.junit.Test; 20 | import org.mrpdaemon.sec.encfs.EncFSUtil; 21 | 22 | import java.nio.ByteBuffer; 23 | import java.util.Random; 24 | 25 | public class EncFSUtilTest { 26 | @Test 27 | public void testInt_99() { 28 | int testInt = 99; 29 | ByteBuffer b = ByteBuffer.allocate(Integer.SIZE / 8).putInt(testInt); 30 | 31 | Assert.assertArrayEquals(b.array(), 32 | EncFSUtil.convertIntToByteArrayBigEndian(testInt)); 33 | Assert.assertEquals(testInt, 34 | EncFSUtil.convertBigEndianByteArrayToInt(b.array())); 35 | } 36 | 37 | @Test 38 | public void testLong_1198() { 39 | long testLong = 1198; 40 | ByteBuffer b = ByteBuffer.allocate(Long.SIZE / 8).putLong(testLong); 41 | 42 | Assert.assertArrayEquals(b.array(), 43 | EncFSUtil.convertLongToByteArrayBigEndian(testLong)); 44 | Assert.assertEquals(testLong, 45 | EncFSUtil.convertByteArrayToLong(b.array())); 46 | } 47 | 48 | @Test 49 | public void testRandomIntToBytesAndBack() { 50 | Random random = new Random(); 51 | for (int i = 0; i < 100; i++) { 52 | int iIn = random.nextInt(); 53 | 54 | int iOut1 = toBytesAndBack(iIn); 55 | int iOut2 = toBytesAndBack(-1 * iIn); 56 | 57 | Assert.assertEquals(iIn, iOut1); 58 | Assert.assertEquals(-1 * iIn, iOut2); 59 | } 60 | } 61 | 62 | @Test 63 | public void testRandomLongToBytesAndBack() { 64 | Random random = new Random(); 65 | for (int i = 0; i < 100; i++) { 66 | long lIn = random.nextLong(); 67 | 68 | long lOut1 = toBytesAndBack(lIn); 69 | long lOut2 = toBytesAndBack(-1 * lIn); 70 | 71 | Assert.assertEquals(lIn, lOut1); 72 | Assert.assertEquals(-1 * lIn, lOut2); 73 | } 74 | } 75 | 76 | private long toBytesAndBack(long lIn) { 77 | byte[] b = EncFSUtil.convertLongToByteArrayBigEndian(lIn); 78 | return EncFSUtil.convertByteArrayToLong(b); 79 | } 80 | 81 | private int toBytesAndBack(int iIn) { 82 | byte[] b = EncFSUtil.convertIntToByteArrayBigEndian(iIn); 83 | return EncFSUtil.convertBigEndianByteArrayToInt(b); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/org/mrpdaemon/sec/encfs/tests/EncFSVolumeFileTest.java: -------------------------------------------------------------------------------- 1 | package org.mrpdaemon.sec.encfs.tests; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.mrpdaemon.sec.encfs.EncFSLocalFileProvider; 6 | 7 | import java.io.File; 8 | 9 | public class EncFSVolumeFileTest extends EncFSVolumeTest { 10 | 11 | private File tempDir; 12 | 13 | @Before 14 | public void setUp() throws Exception { 15 | tempDir = EncFSVolumeTestCommon.createTempDir(); 16 | EncFSLocalFileProvider fileProvider = new EncFSLocalFileProvider( 17 | tempDir); 18 | setFileProvider(fileProvider); 19 | } 20 | 21 | private void recursiveDelete(File file) { 22 | if (file.isDirectory()) { 23 | for (File subFile : file.listFiles()) { 24 | recursiveDelete(subFile); 25 | } 26 | } else { 27 | file.delete(); 28 | } 29 | } 30 | 31 | @After 32 | public void tearDown() throws Exception { 33 | recursiveDelete(tempDir); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/org/mrpdaemon/sec/encfs/tests/EncFSVolumeTest.java: -------------------------------------------------------------------------------- 1 | package org.mrpdaemon.sec.encfs.tests; 2 | 3 | import junit.framework.Assert; 4 | import org.junit.Test; 5 | import org.mrpdaemon.sec.encfs.*; 6 | 7 | public abstract class EncFSVolumeTest { 8 | private EncFSFileProvider fileProvider; 9 | 10 | void setFileProvider(EncFSFileProvider encFSFileProvider) { 11 | this.fileProvider = encFSFileProvider; 12 | } 13 | 14 | EncFSFileProvider getFileProvider() { 15 | return fileProvider; 16 | } 17 | 18 | @Test 19 | public void testNoExistingConfigFile() throws Exception { 20 | try { 21 | new EncFSVolumeBuilder().withFileProvider(fileProvider) 22 | .withDerivedKeyData(new byte[] {}); 23 | } catch (EncFSInvalidConfigException e) { 24 | Assert.assertEquals("No EncFS configuration file found", 25 | e.getMessage()); 26 | } 27 | } 28 | 29 | @Test 30 | public void testVolumeCreation() throws Exception { 31 | EncFSConfig config = EncFSConfigFactory.createDefault(); 32 | 33 | EncFSVolume volume = EncFSVolumeTestCommon.createVolume(config, 34 | fileProvider); 35 | Assert.assertNotNull(volume); 36 | Assert.assertEquals(1, 37 | fileProvider.listFiles(fileProvider.getFilesystemRootPath()) 38 | .size()); 39 | Assert.assertTrue(fileProvider.exists(fileProvider 40 | .getFilesystemRootPath() + ".encfs6.xml")); 41 | } 42 | 43 | @Test 44 | public void testDefaultVolume() throws Exception { 45 | EncFSConfig config = EncFSConfigFactory.createDefault(); 46 | 47 | testFileOperations(config); 48 | } 49 | 50 | @Test 51 | public void testNoUniqueIV() throws Exception { 52 | EncFSConfig config = EncFSConfigFactory.createDefault(); 53 | config.setUseUniqueIV(false); 54 | 55 | testFileOperations(config); 56 | } 57 | 58 | @Test 59 | public void testNoChainedIV() throws Exception { 60 | EncFSConfig config = EncFSConfigFactory.createDefault(); 61 | config.setChainedNameIV(false); 62 | 63 | testFileOperations(config); 64 | } 65 | 66 | @Test 67 | public void testNoUniqueOrChainedIV() throws Exception { 68 | EncFSConfig config = EncFSConfigFactory.createDefault(); 69 | config.setChainedNameIV(false); 70 | config.setUseUniqueIV(false); 71 | 72 | testFileOperations(config); 73 | } 74 | 75 | @Test 76 | public void testNoHolesWithZeroBlockPassThrough() throws Exception { 77 | EncFSConfig config = EncFSConfigFactory.createDefault(); 78 | config.setHolesAllowedInFiles(false); 79 | 80 | testFileOperations(config); 81 | } 82 | 83 | @Test 84 | public void test256BitKey() throws Exception { 85 | EncFSConfig config = EncFSConfigFactory.createDefault(); 86 | config.setVolumeKeySizeInBits(256); 87 | 88 | testFileOperations(config); 89 | } 90 | 91 | @Test 92 | public void test128BitKey() throws Exception { 93 | EncFSConfig config = EncFSConfigFactory.createDefault(); 94 | config.setVolumeKeySizeInBits(128); 95 | 96 | testFileOperations(config); 97 | } 98 | 99 | @Test 100 | public void test4096ByteBlocks() throws Exception { 101 | EncFSConfig config = EncFSConfigFactory.createDefault(); 102 | config.setEncryptedFileBlockSizeInBytes(4096); 103 | 104 | testFileOperations(config); 105 | } 106 | 107 | @Test 108 | public void testStreamNameAlg() throws Exception { 109 | EncFSConfig config = EncFSConfigFactory.createDefault(); 110 | config.setFilenameAlgorithm(EncFSFilenameEncryptionAlgorithm.STREAM); 111 | 112 | testFileOperations(config); 113 | } 114 | 115 | @Test 116 | public void testBlockMAC() throws Exception { 117 | EncFSConfig config = EncFSConfigFactory.createDefault(); 118 | config.setNumberOfMACBytesForEachFileBlock(8); 119 | 120 | testFileOperations(config); 121 | } 122 | 123 | @Test 124 | public void testBlockMACWithRandBytes() throws Exception { 125 | EncFSConfig config = EncFSConfigFactory.createDefault(); 126 | config.setNumberOfMACBytesForEachFileBlock(8); 127 | config.setNumberOfRandomBytesInEachMACHeader(8); 128 | 129 | testFileOperations(config); 130 | } 131 | 132 | private void testFileOperations(EncFSConfig config) throws Exception { 133 | EncFSVolume volume = EncFSVolumeTestCommon.createVolume(config, 134 | fileProvider); 135 | EncFSVolumeTestCommon.testFileOperations(volume); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/test/java/org/mrpdaemon/sec/encfs/tests/EncFSVolumeTestCommon.java: -------------------------------------------------------------------------------- 1 | package org.mrpdaemon.sec.encfs.tests; 2 | 3 | import junit.framework.Assert; 4 | import org.mrpdaemon.sec.encfs.*; 5 | 6 | import java.io.File; 7 | import java.io.FileNotFoundException; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.util.*; 11 | 12 | class EncFSVolumeTestCommon { 13 | private final static String password = "testPassword"; 14 | 15 | public static File createTempDir() throws IOException { 16 | File temp; 17 | 18 | temp = File.createTempFile("encfs-java-tmp", 19 | Long.toString(System.nanoTime())); 20 | if (!temp.delete()) { 21 | throw new IOException("Could not delete temporary file " 22 | + temp.getAbsolutePath()); 23 | } 24 | 25 | if (!temp.mkdir()) { 26 | throw new IOException("Could not create temporary directory"); 27 | } 28 | 29 | return temp; 30 | } 31 | 32 | public static EncFSVolume createVolume(EncFSConfig config, 33 | EncFSFileProvider fileProvider) throws Exception { 34 | try { 35 | new EncFSVolumeBuilder().withFileProvider(fileProvider) 36 | .withConfig(config).withPassword(password) 37 | .writeVolumeConfig(); 38 | // EncFSVolume.createVolume(fileProvider, config, password); 39 | return new EncFSVolumeBuilder().withFileProvider(fileProvider) 40 | .withConfig(config).withPassword(password).buildVolume(); 41 | } catch (Exception e) { 42 | Assert.fail(e.getMessage()); 43 | throw e; 44 | } 45 | } 46 | 47 | private static class EncFSFileInfoComparator implements 48 | Comparator { 49 | @Override 50 | public int compare(EncFSFileInfo info1, EncFSFileInfo info2) { 51 | return info1.getName().compareTo(info2.getName()); 52 | } 53 | } 54 | 55 | private static class EncFSFileComparator implements Comparator { 56 | @Override 57 | public int compare(EncFSFile file1, EncFSFile file2) { 58 | return file1.getName().compareTo(file2.getName()); 59 | } 60 | } 61 | 62 | public static void testFileOperations(EncFSVolume volume) 63 | throws EncFSCorruptDataException, EncFSUnsupportedException, 64 | IOException { 65 | // Create a file 66 | Assert.assertFalse(volume.pathExists("/test.txt")); 67 | Assert.assertEquals(0, 68 | volume.listFilesForPath(EncFSVolume.ROOT_PATH).length); 69 | EncFSFile outFile = volume.createFile("/test.txt"); 70 | EncFSOutputStream os = outFile.openOutputStream(11); 71 | try { 72 | os.write("hello\nworld".getBytes()); 73 | } finally { 74 | os.close(); 75 | } 76 | 77 | // Check the file got created 78 | Assert.assertEquals(1, 79 | volume.listFilesForPath(EncFSVolume.ROOT_PATH).length); 80 | Assert.assertEquals( 81 | 2, 82 | volume.getFileProvider() 83 | .listFiles( 84 | volume.getFileProvider() 85 | .getFilesystemRootPath()).size()); // 1 86 | // for 87 | // the 88 | // config 89 | // file & 1 90 | // data file 91 | EncFSFile encFsFile = volume.getFile("/test.txt"); 92 | Assert.assertNotNull(encFsFile); 93 | Assert.assertEquals("test.txt", encFsFile.getName()); 94 | Assert.assertEquals("/test.txt", encFsFile.getPath()); 95 | Assert.assertTrue(encFsFile.getLength() > 0); 96 | long contentsLength = encFsFile.getLength(); 97 | 98 | // Check that it's name is encrypted 99 | List fileList = volume.getFileProvider().listFiles( 100 | volume.getFileProvider().getFilesystemRootPath()); 101 | Collections.sort(fileList, new EncFSFileInfoComparator()); 102 | if (fileList.get(0).getName().equals(EncFSVolume.CONFIG_FILE_NAME)) { 103 | Assert.assertFalse(fileList.get(1).getName().equals("test.txt")); 104 | } else { 105 | Assert.assertEquals(EncFSVolume.CONFIG_FILE_NAME, fileList.get(1) 106 | .getName()); 107 | Assert.assertFalse(fileList.get(1).getName().equals("test.txt")); 108 | } 109 | 110 | String encFileName = fileList.get(1).getName(); 111 | 112 | // Now rename / move the file 113 | boolean moveResult = volume.movePath(encFsFile.getPath(), "/test2.txt"); 114 | Assert.assertTrue(moveResult); 115 | 116 | // Check that the file name has changed 117 | List fileList2 = volume.getFileProvider().listFiles( 118 | volume.getFileProvider().getFilesystemRootPath()); 119 | Collections.sort(fileList2, new EncFSFileInfoComparator()); 120 | if (fileList2.get(0).getName().equals(EncFSVolume.CONFIG_FILE_NAME)) { 121 | // File at index 1 must have changed 122 | Assert.assertFalse(fileList2.get(1).getName().equals("test.txt")); 123 | Assert.assertFalse(fileList2.get(1).getName().equals(encFileName)); 124 | } else { 125 | Assert.assertEquals(EncFSVolume.CONFIG_FILE_NAME, fileList2.get(1) 126 | .getName()); 127 | // File at index 0 must have changed 128 | Assert.assertFalse(fileList2.get(0).getName().equals("test.txt")); 129 | Assert.assertFalse(fileList2.get(0).getName().equals(encFileName)); 130 | } 131 | 132 | // Try re-moving the original file (should fail as we just moved it) 133 | try { 134 | boolean moveResult2 = volume.movePath(encFsFile.getPath(), 135 | "/test3.txt"); 136 | Assert.assertFalse(moveResult2); 137 | } catch (FileNotFoundException e) { 138 | // Some file providers throw exceptions instead of returning false 139 | } 140 | 141 | // now get the proper file (that we moved the orig to) 142 | encFsFile = volume.getFile("/test2.txt"); 143 | Assert.assertEquals("test2.txt", encFsFile.getName()); 144 | Assert.assertEquals("/test2.txt", encFsFile.getPath()); 145 | 146 | // Try moving to a non-existant directory 147 | try { 148 | boolean moveResult3 = volume.movePath(encFsFile.getPath(), 149 | "/dir1/t.txt"); 150 | Assert.assertFalse(moveResult3); 151 | } catch (FileNotFoundException e) { 152 | // Some file providers throw exceptions instead of returning false 153 | } 154 | 155 | // Make dir1 156 | boolean mkdirResult = volume.makeDir("/dir1"); 157 | Assert.assertTrue(mkdirResult); 158 | 159 | // Check the dir got created 160 | ArrayList volumeFileList = new ArrayList( 161 | Arrays.asList(volume.listFilesForPath(EncFSVolume.ROOT_PATH))); 162 | Collections.sort(volumeFileList, new EncFSFileComparator()); 163 | Assert.assertEquals(2, volumeFileList.size()); 164 | Assert.assertEquals(true, volumeFileList.get(0).isDirectory()); 165 | Assert.assertEquals(false, volumeFileList.get(1).isDirectory()); 166 | 167 | // Try to make the same dir again (it should fail) 168 | try { 169 | boolean mkdirResult2 = volume.makeDir("/dir1"); 170 | Assert.assertFalse(mkdirResult2); 171 | } catch (FileNotFoundException e) { 172 | // Some file providers throw exceptions instead of returning false 173 | } 174 | 175 | // Try to make a dir where the parent doesn't exist (it should fail) 176 | try { 177 | boolean mkdirResult3 = volume.makeDir("/dir2/def"); 178 | Assert.assertFalse(mkdirResult3); 179 | } catch (FileNotFoundException e) { 180 | // Some file providers throw exceptions instead of returning false 181 | } 182 | 183 | // Move the file we created in to this sub directory 184 | boolean moveToDirResult = volume.movePath(encFsFile.getPath(), 185 | "/dir1/test.txt"); 186 | Assert.assertTrue(moveToDirResult); 187 | encFsFile = volume.getFile("/dir1/test.txt"); 188 | Assert.assertEquals("test.txt", encFsFile.getName()); 189 | Assert.assertEquals("/dir1/test.txt", encFsFile.getPath()); 190 | Assert.assertEquals(contentsLength, encFsFile.getLength()); 191 | 192 | // Check the file was moved 193 | volumeFileList = new ArrayList(Arrays.asList(volume 194 | .listFilesForPath(EncFSVolume.ROOT_PATH))); 195 | Collections.sort(volumeFileList, new EncFSFileComparator()); 196 | Assert.assertEquals(1, volumeFileList.size()); 197 | Assert.assertEquals("dir1", volumeFileList.get(0).getName()); 198 | volumeFileList = new ArrayList(Arrays.asList(volume 199 | .listFilesForPath("/dir1"))); 200 | Collections.sort(volumeFileList, new EncFSFileComparator()); 201 | Assert.assertEquals(1, volumeFileList.size()); 202 | Assert.assertEquals("test.txt", volumeFileList.get(0).getName()); 203 | 204 | // Now do a copy to a new nested directory 205 | boolean mkdirsResult = volume.makeDirs("/dir2/dir3"); 206 | Assert.assertTrue(mkdirsResult); 207 | boolean copyResult = volume.copyPath("/dir1/test.txt", "/dir2/dir3"); 208 | Assert.assertTrue(copyResult); 209 | volumeFileList = new ArrayList(Arrays.asList(volume 210 | .listFilesForPath("/dir1"))); 211 | Collections.sort(volumeFileList, new EncFSFileComparator()); 212 | Assert.assertEquals("test.txt", volumeFileList.get(0).getName()); 213 | volumeFileList = new ArrayList(Arrays.asList(volume 214 | .listFilesForPath("/dir2/dir3"))); 215 | Collections.sort(volumeFileList, new EncFSFileComparator()); 216 | Assert.assertEquals("test.txt", volumeFileList.get(0).getName()); 217 | Assert.assertEquals(contentsLength, volume.getFile("/dir1/test.txt") 218 | .getLength()); 219 | Assert.assertEquals(contentsLength, 220 | volume.getFile("/dir2/dir3/test.txt").getLength()); 221 | 222 | // Try to recursively copy a directory 223 | boolean recursiveCopyResult = volume.copyPath("/dir1", "/dir2"); 224 | Assert.assertTrue(recursiveCopyResult); 225 | recursiveCopyResult = volume.pathExists("/dir2/dir1"); 226 | Assert.assertTrue(recursiveCopyResult); 227 | recursiveCopyResult = volume.pathExists("/dir2/dir1/test.txt"); 228 | Assert.assertTrue(recursiveCopyResult); 229 | // Delete the recursively copied directory 230 | recursiveCopyResult = volume.deletePath("/dir2/dir1", true); 231 | Assert.assertTrue(recursiveCopyResult); 232 | 233 | // Delete the src file 234 | boolean deleteFileResult = volume.deletePath("/dir1/test.txt", false); 235 | Assert.assertTrue(deleteFileResult); 236 | 237 | // Check the file has been removed 238 | Assert.assertEquals(2, 239 | volume.listFilesForPath(EncFSVolume.ROOT_PATH).length); 240 | volumeFileList = new ArrayList(Arrays.asList(volume 241 | .listFilesForPath(EncFSVolume.ROOT_PATH))); 242 | Collections.sort(volumeFileList, new EncFSFileComparator()); 243 | Assert.assertEquals("dir1", volumeFileList.get(0).getName()); 244 | Assert.assertEquals("dir2", volumeFileList.get(1).getName()); 245 | Assert.assertEquals(0, volume.listFilesForPath("/dir1").length); 246 | Assert.assertEquals(1, volume.listFilesForPath("/dir2").length); 247 | Assert.assertEquals(1, volume.listFilesForPath("/dir2/dir3").length); 248 | volumeFileList = new ArrayList(Arrays.asList(volume 249 | .listFilesForPath("/dir2/dir3"))); 250 | Collections.sort(volumeFileList, new EncFSFileComparator()); 251 | Assert.assertEquals("test.txt", volumeFileList.get(0).getName()); 252 | 253 | // now delete the empty directory 254 | boolean deleteEmptyDirResult = volume.deletePath("/dir1", false); 255 | Assert.assertTrue(deleteEmptyDirResult); 256 | 257 | // recreate the directory 258 | mkdirResult = volume.makeDir("/dir1"); 259 | Assert.assertTrue(mkdirResult); 260 | 261 | // Copy the file back under it 262 | copyResult = volume.copyPath("/dir2/dir3/test.txt", "/dir1"); 263 | Assert.assertTrue(copyResult); 264 | 265 | // Create a few more directories to test recursive deletion 266 | mkdirsResult = volume.makeDirs("/dir1/dir4/dir5/dir6/dir7"); 267 | Assert.assertTrue(mkdirsResult); 268 | 269 | // Attempt to recursively delete the directory - should succeed 270 | boolean deleteRecursiveResult = volume.deletePath("/dir1", true); 271 | Assert.assertTrue(deleteRecursiveResult); 272 | 273 | // Check the directory has been removed 274 | Assert.assertEquals(1, 275 | volume.listFilesForPath(EncFSVolume.ROOT_PATH).length); 276 | Assert.assertEquals("dir2", 277 | volume.listFilesForPath(EncFSVolume.ROOT_PATH)[0].getName()); 278 | Assert.assertEquals(1, volume.listFilesForPath("/dir2").length); 279 | Assert.assertEquals(1, volume.listFilesForPath("/dir2/dir3").length); 280 | volumeFileList = new ArrayList(Arrays.asList(volume 281 | .listFilesForPath("/dir2/dir3"))); 282 | Collections.sort(volumeFileList, new EncFSFileComparator()); 283 | Assert.assertEquals("test.txt", volumeFileList.get(0).getName()); 284 | 285 | // Read the contents of the file to check that it's been copied / moved 286 | // around OK 287 | InputStream is = volume.openInputStreamForPath("/dir2/dir3/test.txt"); 288 | try { 289 | StringBuilder sb = new StringBuilder(); 290 | int bytesRead = 0; 291 | while (bytesRead >= 0) { 292 | byte[] readBuf = new byte[128]; 293 | bytesRead = is.read(readBuf); 294 | if (bytesRead > 0) { 295 | sb.append(new String(readBuf, 0, bytesRead)); 296 | } 297 | } 298 | 299 | String readContents = sb.toString(); 300 | Assert.assertEquals("hello\nworld", readContents); 301 | } finally { 302 | is.close(); 303 | } 304 | 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /src/test/java/org/mrpdaemon/sec/encfs/tests/EncFSVolumeVFSTest.java: -------------------------------------------------------------------------------- 1 | package org.mrpdaemon.sec.encfs.tests; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.mrpdaemon.sec.encfs.tests.vfs.CommonsVFSRamFileProvider; 6 | 7 | public class EncFSVolumeVFSTest extends EncFSVolumeTest { 8 | 9 | @Before 10 | public void setUp() throws Exception { 11 | CommonsVFSRamFileProvider fileProvider = new CommonsVFSRamFileProvider(); 12 | fileProvider.init(); 13 | setFileProvider(fileProvider); 14 | } 15 | 16 | @After 17 | public void tearDown() throws Exception { 18 | ((CommonsVFSRamFileProvider) getFileProvider()).close(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/org/mrpdaemon/sec/encfs/tests/vfs/CommonsVFSFileProvider.java: -------------------------------------------------------------------------------- 1 | package org.mrpdaemon.sec.encfs.tests.vfs; 2 | 3 | import org.apache.commons.vfs2.*; 4 | import org.mrpdaemon.sec.encfs.EncFSFileInfo; 5 | import org.mrpdaemon.sec.encfs.EncFSFileProvider; 6 | import org.mrpdaemon.sec.encfs.EncFSVolume; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.OutputStream; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public class CommonsVFSFileProvider implements EncFSFileProvider { 15 | 16 | private final String separator; 17 | 18 | final FileSystemManager fileSystemManager; 19 | 20 | CommonsVFSFileProvider(FileSystemManager fileSystemManager) { 21 | this.fileSystemManager = fileSystemManager; 22 | this.separator = FileName.SEPARATOR; 23 | } 24 | 25 | public final String getSeparator() { 26 | return separator; 27 | } 28 | 29 | public final String getFilesystemRootPath() { 30 | return FileName.ROOT_PATH; 31 | } 32 | 33 | public boolean move(String encOrigFileName, String encNewFileName) 34 | throws IOException { 35 | FileObject origFile = resolveFile(encOrigFileName); 36 | if (!origFile.exists()) 37 | return false; 38 | 39 | FileObject newFile = resolveFile(encNewFileName); 40 | if (encNewFileName.lastIndexOf(separator) > 0) { 41 | if (!newFile.getParent().exists()) { 42 | return false; 43 | } 44 | } 45 | origFile.moveTo(newFile); 46 | return true; 47 | } 48 | 49 | private FileObject resolveFile(String encOrigFileName) 50 | throws FileSystemException { 51 | return fileSystemManager.resolveFile(fileSystemManager.getSchemes()[0] 52 | + ":" + encOrigFileName); 53 | } 54 | 55 | public boolean isDirectory(String encFileName) throws IOException { 56 | FileObject file = resolveFile(encFileName); 57 | return file.getType() == FileType.FOLDER; 58 | } 59 | 60 | public boolean delete(String encFileName) throws IOException { 61 | FileObject file = resolveFile(encFileName); 62 | return file.delete(); 63 | } 64 | 65 | public boolean mkdir(String encDirName) throws IOException { 66 | FileObject file = resolveFile(encDirName); 67 | if (file.exists()) { 68 | return false; 69 | } else { 70 | if (encDirName.lastIndexOf(separator) != 0) { 71 | if (!file.getParent().exists()) { 72 | return false; 73 | } 74 | } 75 | file.createFolder(); 76 | return true; 77 | } 78 | } 79 | 80 | public boolean mkdirs(String encDirName) throws IOException { 81 | String[] dirNameParts = encDirName.split(separator); 82 | 83 | String tmpDirName = ""; 84 | for (String dirNamePart : dirNameParts) { 85 | if (!tmpDirName.endsWith(separator)) { 86 | tmpDirName += separator; 87 | } 88 | tmpDirName += dirNamePart; 89 | 90 | FileObject tmpDirFile = resolveFile(tmpDirName); 91 | boolean partResult = true; 92 | if (!tmpDirFile.exists()) { 93 | partResult = mkdir(tmpDirName); 94 | } else if (tmpDirFile.getType() == FileType.FILE) { 95 | partResult = false; 96 | } 97 | 98 | if (!partResult) { 99 | return false; 100 | } 101 | } 102 | 103 | return true; 104 | } 105 | 106 | public boolean copy(String encSrcFileName, String encTargetFileName) 107 | throws IOException { 108 | FileObject srcFile = resolveFile(encSrcFileName); 109 | FileObject targetFile = resolveFile(encTargetFileName); 110 | 111 | FileUtil.copyContent(srcFile, targetFile); 112 | return true; 113 | } 114 | 115 | public List listFiles(String encDirName) throws IOException { 116 | FileObject srcDir = resolveFile(encDirName); 117 | FileObject[] children = srcDir.getChildren(); 118 | 119 | List result = new ArrayList( 120 | children.length); 121 | for (FileObject aChildren : children) { 122 | result.add(getFileInfo(aChildren)); 123 | } 124 | 125 | return result; 126 | } 127 | 128 | public InputStream openInputStream(String encSrcFile) throws IOException { 129 | FileObject srcFile = resolveFile(encSrcFile); 130 | return srcFile.getContent().getInputStream(); 131 | } 132 | 133 | public OutputStream openOutputStream(String encSrcFile, long outputLength) 134 | throws IOException { 135 | FileObject srcFile = resolveFile(encSrcFile); 136 | return srcFile.getContent().getOutputStream(); 137 | } 138 | 139 | public EncFSFileInfo getFileInfo(String encSrcFile) throws IOException { 140 | FileObject srcFile = resolveFile(encSrcFile); 141 | return getFileInfo(srcFile); 142 | } 143 | 144 | public boolean exists(String encSrcFile) throws IOException { 145 | FileObject srcFile = resolveFile(encSrcFile); 146 | return srcFile.exists(); 147 | } 148 | 149 | private EncFSFileInfo getFileInfo(FileObject fileObject) throws IOException { 150 | String name = fileObject.getName().getBaseName(); 151 | String volumePath = fileObject.getName().getPath(); 152 | volumePath = volumePath.substring(0, 153 | volumePath.length() - (name.length() + 1)); 154 | if (volumePath.equals("")) { 155 | volumePath = EncFSVolume.ROOT_PATH; 156 | } 157 | 158 | boolean isDirectory = fileObject.getType() == FileType.FOLDER; 159 | long modified = fileObject.getContent().getLastModifiedTime(); 160 | long size = (isDirectory ? 0 : fileObject.getContent().getSize()); 161 | boolean canRead = fileObject.isReadable(); 162 | boolean canWrite = fileObject.isWriteable(); 163 | boolean canExecute = false; 164 | 165 | return new EncFSFileInfo(name, volumePath, isDirectory, modified, size, 166 | canRead, canWrite, canExecute); 167 | } 168 | 169 | public EncFSFileInfo createFile(String encTargetFile) throws IOException { 170 | if (exists(encTargetFile)) { 171 | throw new IOException("File already exists"); 172 | } 173 | 174 | FileObject targetFile = resolveFile(encTargetFile); 175 | targetFile.createFile(); 176 | 177 | return getFileInfo(targetFile); 178 | } 179 | 180 | } 181 | -------------------------------------------------------------------------------- /src/test/java/org/mrpdaemon/sec/encfs/tests/vfs/CommonsVFSRamFileProvider.java: -------------------------------------------------------------------------------- 1 | package org.mrpdaemon.sec.encfs.tests.vfs; 2 | 3 | import org.apache.commons.vfs2.FileSystemException; 4 | import org.apache.commons.vfs2.impl.DefaultFileSystemManager; 5 | import org.apache.commons.vfs2.provider.ram.RamFileProvider; 6 | 7 | import java.io.IOException; 8 | 9 | public class CommonsVFSRamFileProvider extends CommonsVFSFileProvider { 10 | 11 | private DefaultFileSystemManager fileSystemManager; 12 | 13 | public CommonsVFSRamFileProvider() { 14 | super(createFileSystemManager()); 15 | this.fileSystemManager = (DefaultFileSystemManager) super.fileSystemManager; 16 | } 17 | 18 | private static DefaultFileSystemManager createFileSystemManager() { 19 | RamFileProvider ramFileProvider = new RamFileProvider(); 20 | DefaultFileSystemManager fileSystemManager = new DefaultFileSystemManager(); 21 | // this.fileSystemManager.setLogger(log); 22 | try { 23 | fileSystemManager.addProvider("ram", ramFileProvider); 24 | fileSystemManager.setDefaultProvider(ramFileProvider); 25 | } catch (FileSystemException e) { 26 | throw new IllegalStateException(e); 27 | } 28 | 29 | return fileSystemManager; 30 | } 31 | 32 | public void init() throws IOException { 33 | fileSystemManager.init(); 34 | } 35 | 36 | public void close() { 37 | fileSystemManager.close(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/encfs_samples/Samples.txt: -------------------------------------------------------------------------------- 1 | Volumes created via EncFS 1.7.4: 2 | 3 | testvol-default -- Default parameters (non-expert mode) 4 | Enter password: test 5 | / > ls 6 | longfile.txt 7 | test.txt 8 | zerofile.bin 9 | / > cat test.txt 10 | This is a test file. 11 | 12 | testvol-nouniqueiv -- Test volume without unique IV (no per-file IV header) 13 | Enter password: test 14 | / > ls 15 | longfile.txt 16 | testfile.txt 17 | / > cat testfile.txt 18 | Test file for non-unique-IV file. 19 | 20 | testvol-blockmac -- Test volume using block-level MAC to verify file contents 21 | Enter password: test 22 | / > ls 23 | longfile.txt 24 | / > cat longfile.txt 25 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 26 | 27 | testvol-streamname - Test volume for nameio/stream name algorithm 28 | Enter password: test 29 | / > ls 30 | dir/ 31 | / > cd dir 32 | /dir > ls 33 | testfile.txt 34 | /dir > cat testfile.txt 35 | stream name algorithm 36 | 37 | testvol-extivchn - Test volume with external IV chaining (paranoia mode w/ encfs) 38 | Enter password: test 39 | / > ls 40 | directory/ 41 | test.txt 42 | / > cat test.txt 43 | this is a test file with external IV chaining 44 | / > cd directory 45 | /directory > ls 46 | another-test-file.txt 47 | /directory > cat another-test-file.txt 48 | this is another test file with external IV chaining 49 | 50 | Volumes created via BoxCryptor: 51 | 52 | boxcryptor_1 -- A simple encfs sample with a single test file 53 | Enter password: test 54 | / > ls 55 | .encfs6.xml 56 | testfile.txt 57 | / > cat testfile.txt 58 | test file 59 | 60 | boxcryptor_2 -- Another sample with a different password & a nested folder 61 | Enter password: test2 62 | / > ls 63 | .encfs6.xml 64 | Dir1/ 65 | file1.txt 66 | / > cat file1.txt 67 | Some contents for file 68 | 69 | boxcryptor_3 -- raw files contains a file that doens't belong to the encfs_volume (in this case desktop.ini from windows folder customisation) 70 | Enter password: test 71 | / > ls 72 | .encfs6.xml 73 | testFileAlpha.txt.txt 74 | / > cat testFileAlpha.txt.txt 75 | Contents for test fileAlpha.tx 76 | 77 | boxcryptor_null -- volume using nameio/null filename encoding 78 | Enter password: test 79 | / > ls 80 | testfile.txt 81 | / > cat testfile.txt 82 | Contents for test fileAlpha.txt -------------------------------------------------------------------------------- /test/encfs_samples/boxcryptor_1/.encfs6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20100713 6 | BoxCryptor 1.0.0.0 7 | 8 | ssl/aes 9 | 3 10 | 0 11 | 12 | 13 | nameio/stream 14 | 2 15 | 1 16 | 17 | 256 18 | 4096 19 | 0 20 | 0 21 | 0 22 | 0 23 | 0 24 | 1 25 | 52 26 | p8hapetrpqIyAxe/9mLE/nNGFFWugkLiTn1g+bAA1NMOwnD4YhcI6xc3ObQ8df1NoFVh8A== 27 | 20 28 | 106QqKPzGADnhiVHOYtgv0PbiUs= 29 | 5000 30 | 500 31 | 32 | -------------------------------------------------------------------------------- /test/encfs_samples/boxcryptor_1/W3gLoUqL-0YzUh8udP8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/boxcryptor_1/W3gLoUqL-0YzUh8udP8 -------------------------------------------------------------------------------- /test/encfs_samples/boxcryptor_2/.encfs6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20100713 6 | BoxCryptor 1.0.0.0 7 | 8 | ssl/aes 9 | 3 10 | 0 11 | 12 | 13 | nameio/stream 14 | 2 15 | 1 16 | 17 | 256 18 | 4096 19 | 0 20 | 0 21 | 0 22 | 0 23 | 0 24 | 1 25 | 52 26 | Vagdpbqb98kWpbqPdKRZFewX6bKy+WXg7cd325/ea6oaA+cav69Wlvc8uL++0W1ZiRJGOg== 27 | 20 28 | GlHva0+8s0Izdez0a2Zy4+zYq1U= 29 | 5000 30 | 500 31 | 32 | -------------------------------------------------------------------------------- /test/encfs_samples/boxcryptor_2/Z4Qzgr-iwj-1dgA: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/boxcryptor_2/Z4Qzgr-iwj-1dgA -------------------------------------------------------------------------------- /test/encfs_samples/boxcryptor_2/hc2yatLg/lcgwUaXICbCjBW4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/boxcryptor_2/hc2yatLg/lcgwUaXICbCjBW4 -------------------------------------------------------------------------------- /test/encfs_samples/boxcryptor_3/.encfs6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20100713 6 | BoxCryptor 1.0.0.0 7 | 8 | ssl/aes 9 | 3 10 | 0 11 | 12 | 13 | nameio/stream 14 | 2 15 | 1 16 | 17 | 256 18 | 4096 19 | 0 20 | 0 21 | 0 22 | 0 23 | 0 24 | 1 25 | 52 26 | oZxF/rvM3gexO3TNxaAZvBm/nsMzxm+2eLAFR7IfLBuOfziqgjyt4MEjWfGZEQEyhyRUig== 27 | 20 28 | NFehLBmSc50W+R9QPVPDdWU/5AE= 29 | 5000 30 | 500 31 | 32 | -------------------------------------------------------------------------------- /test/encfs_samples/boxcryptor_3/cJTbxx2GhjzRDYYra4twBcIr0-pPGtD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/boxcryptor_3/cJTbxx2GhjzRDYYra4twBcIr0-pPGtD -------------------------------------------------------------------------------- /test/encfs_samples/boxcryptor_3/desktop.ini: -------------------------------------------------------------------------------- 1 | [.ShellClassInfo] 2 | IconResource=C:\Windows\system32\SHELL32.dll,27 3 | [ViewState] 4 | Mode= 5 | Vid= 6 | FolderType=Documents 7 | -------------------------------------------------------------------------------- /test/encfs_samples/boxcryptor_null/.encfs6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20100713 6 | BoxCryptor 1.3.2.0 7 | 8 | ssl/aes 9 | 3 10 | 0 11 | 12 | 13 | nameio/null 14 | 1 15 | 0 16 | 17 | 256 18 | 4096 19 | 0 20 | 0 21 | 0 22 | 0 23 | 0 24 | 1 25 | 52 26 | oZxF/rvM3gexO3TNxaAZvBm/nsMzxm+2eLAFR7IfLBuOfziqgjyt4MEjWfGZEQEyhyRUig== 27 | 20 28 | NFehLBmSc50W+R9QPVPDdWU/5AE= 29 | 5000 30 | 500 31 | 32 | 33 | -------------------------------------------------------------------------------- /test/encfs_samples/boxcryptor_null/testfile.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/boxcryptor_null/testfile.txt -------------------------------------------------------------------------------- /test/encfs_samples/testvol-blockmac/.encfs6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20100713 6 | EncFS 1.7.4 7 | 8 | ssl/aes 9 | 3 10 | 0 11 | 12 | 13 | nameio/block 14 | 3 15 | 0 16 | 17 | 192 18 | 1024 19 | 1 20 | 1 21 | 0 22 | 8 23 | 8 24 | 0 25 | 44 26 | 27 | MdcPVgzw5gWQUu5EVFsG8VaxkAWp8xTmSeBCjJwB/nAmJqEwsL4osY7b6Hw= 28 | 29 | 20 30 | 31 | 2R8IMzmv9INhi1VTC1oQwIhNI/s= 32 | 33 | 252483 34 | 500 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/encfs_samples/testvol-blockmac/85hMcPOogQFKISDxPi,QcvlY: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/testvol-blockmac/85hMcPOogQFKISDxPi,QcvlY -------------------------------------------------------------------------------- /test/encfs_samples/testvol-default/.encfs6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20100713 6 | EncFS 1.7.4 7 | 8 | ssl/aes 9 | 3 10 | 0 11 | 12 | 13 | nameio/block 14 | 3 15 | 0 16 | 17 | 192 18 | 1024 19 | 1 20 | 1 21 | 0 22 | 0 23 | 0 24 | 1 25 | 44 26 | 27 | 36hc1JmVocyDYLcIXLcJSVjC5MQ8Ys6mOH5DE2yEIlaHkbp6FaiuLC8rKL4= 28 | 29 | 20 30 | 31 | Li8XSCZeqCgJZPqnP0Ko2/99gQk= 32 | 33 | 253807 34 | 500 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/encfs_samples/testvol-default/kNmBCW-Coq1CvGZ1EabjsiB4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/testvol-default/kNmBCW-Coq1CvGZ1EabjsiB4 -------------------------------------------------------------------------------- /test/encfs_samples/testvol-default/ko1GW2gcuNSbGWQryepRJpSC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/testvol-default/ko1GW2gcuNSbGWQryepRJpSC -------------------------------------------------------------------------------- /test/encfs_samples/testvol-default/qQQTyqU5n10lZYe-YTOfkTo2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/testvol-default/qQQTyqU5n10lZYe-YTOfkTo2 -------------------------------------------------------------------------------- /test/encfs_samples/testvol-extivchn/.encfs6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20100713 6 | EncFS 1.7.4 7 | 8 | ssl/aes 9 | 3 10 | 0 11 | 12 | 13 | nameio/block 14 | 3 15 | 0 16 | 17 | 256 18 | 1024 19 | 1 20 | 1 21 | 1 22 | 8 23 | 0 24 | 1 25 | 52 26 | 27 | LT6tG7SRgYpVD3bmMAtDs7PAae9NSavH0kBlkMZ/lwBdPw+wrF3LfkbL+eWo4huu00rouA== 28 | 29 | 20 30 | 31 | /7neEwCar1Ipa6AWv566tsDdWT4= 32 | 33 | 1161684 34 | 3000 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/encfs_samples/testvol-extivchn/CjIsKUMxWNJZJ5mLWPboFUb5/FGSPI4b,efiE-vCHTF5-XAmw7jeS35Jy,EgYsJ7nhxwRN-: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/testvol-extivchn/CjIsKUMxWNJZJ5mLWPboFUb5/FGSPI4b,efiE-vCHTF5-XAmw7jeS35Jy,EgYsJ7nhxwRN- -------------------------------------------------------------------------------- /test/encfs_samples/testvol-extivchn/pWxw6SiMcDvaieR0K9IS4f0n: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/testvol-extivchn/pWxw6SiMcDvaieR0K9IS4f0n -------------------------------------------------------------------------------- /test/encfs_samples/testvol-nouniqueiv/.encfs6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20100713 6 | EncFS 1.7.4 7 | 8 | ssl/aes 9 | 3 10 | 0 11 | 12 | 13 | nameio/block 14 | 3 15 | 0 16 | 17 | 256 18 | 1024 19 | 0 20 | 1 21 | 0 22 | 0 23 | 0 24 | 1 25 | 52 26 | 27 | WDbI6faBNx0YwgjGrOHlK/YSq2jfT56MxvXGyEPGJPmuSgbHNAM/jgauneNuGrrzVYyLCQ== 28 | 29 | 20 30 | 31 | NX9m/gl2B9+if+OHAWM4JRSniVI= 32 | 33 | 169700 34 | 500 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/encfs_samples/testvol-nouniqueiv/XSuCblFoZx5WZQFkf3O6E8HS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/testvol-nouniqueiv/XSuCblFoZx5WZQFkf3O6E8HS -------------------------------------------------------------------------------- /test/encfs_samples/testvol-nouniqueiv/fFHqdbodgs8p5Q1NH,pjhHle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/testvol-nouniqueiv/fFHqdbodgs8p5Q1NH,pjhHle -------------------------------------------------------------------------------- /test/encfs_samples/testvol-streamname/.encfs6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20100713 6 | EncFS 1.7.4 7 | 8 | ssl/aes 9 | 3 10 | 0 11 | 12 | 13 | nameio/stream 14 | 2 15 | 1 16 | 17 | 256 18 | 1024 19 | 1 20 | 1 21 | 0 22 | 0 23 | 0 24 | 1 25 | 52 26 | 27 | YEwszW8YpVKtTTDqdjavLVAXt/ILh5hRr6Y+LkADse8j9fgyo3xMB3tPQZoDsLhqbY/k3g== 28 | 29 | 20 30 | 31 | YrRS94/u2lMCDPZE9UZ1lhJHV+A= 32 | 33 | 198018 34 | 500 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/encfs_samples/testvol-streamname/7W2,dU4/H-mMw-IyZnf6SdpOZo,: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrpdaemon/encfs-java/702acc08242314fefe7f921757ea498ff78559cd/test/encfs_samples/testvol-streamname/7W2,dU4/H-mMw-IyZnf6SdpOZo, --------------------------------------------------------------------------------