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:
Mark Pariente 2012-08-14 00:46:32 -07:00
parent dc7d4836f3
commit cdcd5923e8
7 changed files with 93 additions and 8 deletions
src
test/encfs_samples/boxcryptor_null

View file

@ -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;

View file

@ -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: "

View 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";

View file

@ -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;

View file

@ -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;

View 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>

View file

@ -0,0 +1,2 @@
<EFBFBD>"<22><>Fs<46>rq<72>K<><4B><14>Q<EFBFBD><51>^<5E>
<EFBFBD>r<EFBFBD><EFBFBD><EFBFBD><0F>