/*
* EncFS Java Library
* Copyright (C) 2013 encfs-java authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
package org.mrpdaemon.sec.encfs;
import java.util.Arrays;
// Common class for filename decryption strategies
abstract class BasicFilenameDecryptionStrategy extends
FilenameDecryptionStrategy {
BasicFilenameDecryptionStrategy(EncFSVolume volume, String volumePath,
EncFSFilenameEncryptionAlgorithm algorithm) {
super(volume, volumePath, algorithm);
}
// Actual decryption to be implemented by the subclass
protected abstract byte[] decryptConcrete(EncFSVolume volume,
byte[] encFileName, byte[] fileIv) throws EncFSCorruptDataException;
// Filename decryption implementation
protected String decryptImpl(String fileName)
throws EncFSCorruptDataException, EncFSChecksumException {
EncFSVolume volume = getVolume();
String volumePath = getVolumePath();
EncFSConfig config = volume.getConfig();
byte[] chainIv = EncFSCrypto.computeChainedIV(volume, volumePath,
config);
byte[] base256FileName = EncFSBase64.decodeEncfs(fileName.getBytes());
byte[] macBytes;
try {
macBytes = EncFSCrypto.getMacBytes(base256FileName);
} catch (ArrayIndexOutOfBoundsException e) {
/*
* It's possible for fileName to be malformed so as to make
* base256FileName shorter than 2 bytes. In this case, getMacBytes()
* will throw an exception.
*/
throw new EncFSCorruptDataException(e);
}
byte[] encFileName = Arrays.copyOfRange(base256FileName, 2,
base256FileName.length);
byte[] fileIv = EncFSCrypto.computeFileIV(chainIv, macBytes);
byte[] decFileName = decryptConcrete(volume, encFileName, fileIv);
verifyDecryptionWorked(volume, chainIv, base256FileName, decFileName);
return decryptPost(decFileName);
}
// Post decrpytion hook for subclasses
protected abstract String decryptPost(byte[] fileName);
// Verify that the decryption worked
private void verifyDecryptionWorked(EncFSVolume volume, byte[] chainIv,
byte[] base256FileName, byte[] decFileName)
throws EncFSChecksumException {
// Verify decryption worked
// current versions store the checksum at the beginning (encfs 0.x
// stored checksums at the end)
byte[] mac16;
if (volume.getConfig().isChainedNameIV()) {
mac16 = EncFSCrypto.mac16(volume.getMAC(), decFileName, chainIv);
} else {
mac16 = EncFSCrypto.mac16(volume.getMAC(), decFileName);
}
byte[] expectedMac = Arrays.copyOfRange(base256FileName, 0, 2);
if (!Arrays.equals(mac16, expectedMac)) {
throw new EncFSChecksumException("Mismatch in file name checksum");
}
}
}