Implement unencrypted filename support (nameio/null)
BoxCryptor uses an unencrypted name algorithm to encrypt file contents without encrypting filenames. This change implements this algorithm and adds a unit test. Thanks 1jr for requesting this and providing test cases. Also added a volume integration test for this algorithm.
This commit is contained in:
parent
dc7d4836f3
commit
cdcd5923e8
7 changed files with 93 additions and 8 deletions
src
main/java/org/mrpdaemon/sec/encfs
test/java/org/mrpdaemon/sec/encfs
test/encfs_samples/boxcryptor_null
|
@ -26,6 +26,9 @@ public class EncFSConfig {
|
|||
/** Volume configuration uses nameio/stream for filename encryption */
|
||||
public static final int ENCFS_CONFIG_NAME_ALG_STREAM = 2;
|
||||
|
||||
/** Volume configuration uses nameio/null for filename encryption */
|
||||
public final static int ENCFS_CONFIG_NAME_ALG_NULL = 3;
|
||||
|
||||
// Size of the volume encryption key in bits.
|
||||
private int volumeKeySize;
|
||||
|
||||
|
|
|
@ -172,6 +172,8 @@ public class EncFSConfigParser {
|
|||
config.setNameAlgorithm(EncFSConfig.ENCFS_CONFIG_NAME_ALG_BLOCK);
|
||||
} else if (algName.equals("nameio/stream")) {
|
||||
config.setNameAlgorithm(EncFSConfig.ENCFS_CONFIG_NAME_ALG_STREAM);
|
||||
} else if (algName.equals("nameio/null")) {
|
||||
config.setNameAlgorithm(EncFSConfig.ENCFS_CONFIG_NAME_ALG_NULL);
|
||||
} else {
|
||||
throw new EncFSInvalidConfigException(
|
||||
"Unknown name algorithm in config file: "
|
||||
|
|
|
@ -46,11 +46,15 @@ public class EncFSConfigWriter {
|
|||
result += "\t\t<name>nameio/block</name>\n";
|
||||
result += "\t\t<major>3</major>\n";
|
||||
result += "\t\t<minor>0</minor>\n";
|
||||
} else {
|
||||
assert (config.getNameAlgorithm() == EncFSConfig.ENCFS_CONFIG_NAME_ALG_STREAM);
|
||||
} else if (config.getNameAlgorithm() == EncFSConfig.ENCFS_CONFIG_NAME_ALG_STREAM) {
|
||||
result += "\t\t<name>nameio/stream</name>\n";
|
||||
result += "\t\t<major>2</major>\n";
|
||||
result += "\t\t<minor>1</minor>\n";
|
||||
} else {
|
||||
assert (config.getNameAlgorithm() == EncFSConfig.ENCFS_CONFIG_NAME_ALG_NULL);
|
||||
result += "\t\t<name>nameio/null</name>\n";
|
||||
result += "\t\t<major>1</major>\n";
|
||||
result += "\t\t<minor>0</minor>\n";
|
||||
}
|
||||
result += "\t</nameAlg>\n";
|
||||
|
||||
|
|
|
@ -672,28 +672,27 @@ public class EncFSCrypto {
|
|||
String curPath = st.nextToken();
|
||||
if ((curPath.length() > 0)
|
||||
&& (curPath != EncFSVolume.PATH_SEPARATOR)) {
|
||||
|
||||
|
||||
byte[] encodeBytes;
|
||||
|
||||
if (volume.getConfig().getNameAlgorithm() ==
|
||||
EncFSConfig.ENCFS_CONFIG_NAME_ALG_BLOCK) {
|
||||
if (volume.getConfig().getNameAlgorithm() == EncFSConfig.ENCFS_CONFIG_NAME_ALG_BLOCK) {
|
||||
// Only pad for block mode
|
||||
int padLen = 16 - (curPath.length() % 16);
|
||||
if (padLen == 0) {
|
||||
padLen = 16;
|
||||
}
|
||||
encodeBytes = new byte[curPath.length() + padLen];
|
||||
|
||||
|
||||
for (int i = 0; i < curPath.length(); i++) {
|
||||
encodeBytes[i] = curPath.getBytes()[i];
|
||||
}
|
||||
|
||||
|
||||
// Pad to the nearest 16 bytes, add a full block if needed
|
||||
for (int i = 0; i < padLen; i++) {
|
||||
encodeBytes[curPath.length() + i] = (byte) padLen;
|
||||
}
|
||||
} else {
|
||||
encodeBytes = curPath.getBytes();
|
||||
encodeBytes = curPath.getBytes();
|
||||
}
|
||||
|
||||
// Update chain IV
|
||||
|
@ -724,6 +723,17 @@ public class EncFSCrypto {
|
|||
public static String decodeName(EncFSVolume volume, String fileName,
|
||||
String volumePath) throws EncFSCorruptDataException,
|
||||
EncFSChecksumException {
|
||||
|
||||
// No decryption for nameio/null algorithm
|
||||
if (volume.getConfig().getNameAlgorithm() == EncFSConfig.ENCFS_CONFIG_NAME_ALG_NULL) {
|
||||
// Filter out config file
|
||||
if (volumePath.equals(volume.getRootDir().getPath())
|
||||
&& fileName.equals(EncFSVolume.CONFIG_FILE_NAME)) {
|
||||
return null;
|
||||
}
|
||||
return new String(fileName);
|
||||
}
|
||||
|
||||
byte[] base256FileName = EncFSBase64.decodeEncfs(fileName.getBytes());
|
||||
|
||||
byte[] encFileName = Arrays.copyOfRange(base256FileName, 2,
|
||||
|
@ -811,6 +821,12 @@ public class EncFSCrypto {
|
|||
*/
|
||||
public static String encodeName(EncFSVolume volume, String fileName,
|
||||
String volumePath) throws EncFSCorruptDataException {
|
||||
|
||||
// No encryption for nameio/null algorithm
|
||||
if (volume.getConfig().getNameAlgorithm() == EncFSConfig.ENCFS_CONFIG_NAME_ALG_NULL) {
|
||||
return new String(fileName);
|
||||
}
|
||||
|
||||
byte[] decFileName = fileName.getBytes();
|
||||
|
||||
byte[] paddedDecFileName;
|
||||
|
|
|
@ -313,6 +313,32 @@ public class EncFSVolumeIntegrationTest {
|
|||
assertLengthCalculations(rootDir);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoxCryptor_null() throws EncFSInvalidPasswordException,
|
||||
EncFSInvalidConfigException, EncFSCorruptDataException,
|
||||
EncFSUnsupportedException, EncFSChecksumException, IOException {
|
||||
File encFSDir = new File("test/encfs_samples/boxcryptor_null");
|
||||
Assert.assertTrue(encFSDir.exists());
|
||||
|
||||
String password = "test";
|
||||
EncFSVolume volume = new EncFSVolume(encFSDir.getAbsolutePath(),
|
||||
password);
|
||||
EncFSFile rootDir = volume.getRootDir();
|
||||
EncFSFile[] files = rootDir.listFiles();
|
||||
Assert.assertEquals(1, files.length);
|
||||
|
||||
EncFSFile encFSFile = files[0];
|
||||
Assert.assertFalse(encFSFile.isDirectory());
|
||||
Assert.assertEquals("testfile.txt", encFSFile.getName());
|
||||
|
||||
String contents = readInputStreamAsString(encFSFile);
|
||||
Assert.assertEquals("Contents for test fileAlpha.txt", contents);
|
||||
|
||||
assertFileNameEncoding(rootDir);
|
||||
assertEncFSFileRoundTrip(rootDir);
|
||||
assertLengthCalculations(rootDir);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createVolume_1() {
|
||||
File rootDir;
|
||||
|
|
32
test/encfs_samples/boxcryptor_null/.encfs6.xml
Normal file
32
test/encfs_samples/boxcryptor_null/.encfs6.xml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<!DOCTYPE boost_serialization>
|
||||
<boost_serialization signature="serialization::archive" version="7">
|
||||
<cfg class_id="0" tracking_level="0" version="20">
|
||||
<version>20100713</version>
|
||||
<creator>BoxCryptor 1.3.2.0</creator>
|
||||
<cipherAlg class_id="1" tracking_level="0" version="0">
|
||||
<name>ssl/aes</name>
|
||||
<major>3</major>
|
||||
<minor>0</minor>
|
||||
</cipherAlg>
|
||||
<nameAlg>
|
||||
<name>nameio/null</name>
|
||||
<major>1</major>
|
||||
<minor>0</minor>
|
||||
</nameAlg>
|
||||
<keySize>256</keySize>
|
||||
<blockSize>4096</blockSize>
|
||||
<uniqueIV>0</uniqueIV>
|
||||
<chainedNameIV>0</chainedNameIV>
|
||||
<externalIVChaining>0</externalIVChaining>
|
||||
<blockMACBytes>0</blockMACBytes>
|
||||
<blockMACRandBytes>0</blockMACRandBytes>
|
||||
<allowHoles>1</allowHoles>
|
||||
<encodedKeySize>52</encodedKeySize>
|
||||
<encodedKeyData>oZxF/rvM3gexO3TNxaAZvBm/nsMzxm+2eLAFR7IfLBuOfziqgjyt4MEjWfGZEQEyhyRUig== </encodedKeyData>
|
||||
<saltLen>20</saltLen>
|
||||
<saltData>NFehLBmSc50W+R9QPVPDdWU/5AE= </saltData>
|
||||
<kdfIterations>5000</kdfIterations>
|
||||
<desiredKDFDuration>500</desiredKDFDuration>
|
||||
</cfg>
|
||||
</boost_serialization>
|
2
test/encfs_samples/boxcryptor_null/testfile.txt
Normal file
2
test/encfs_samples/boxcryptor_null/testfile.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
<EFBFBD>"<22><>Fs<46>rq<72>K<><4B><14>Q<EFBFBD><51>^<5E>
|
||||
<EFBFBD>r<EFBFBD><EFBFBD><EFBFBD><0F>
|
Loading…
Add table
Add a link
Reference in a new issue