package freenet.node;
import java.io.UnsupportedEncodingException;
import java.util.Random;
import org.bouncycastle.util.Arrays;
import com.db4o.io.IoAdapter;
import freenet.crypt.AEADCryptBucket;
import freenet.crypt.EncryptingIoAdapter;
import freenet.crypt.HMAC;
import freenet.crypt.RandomSource;
import freenet.support.api.Bucket;
public class DatabaseKey {
private final byte[] databaseKey;
private final Random random;
DatabaseKey(byte[] key, Random random) {
this.databaseKey = Arrays.copyOf(key, key.length);
this.random = random;
}
public EncryptingIoAdapter createEncryptingDb4oAdapter(IoAdapter baseAdapter) {
return new EncryptingIoAdapter(baseAdapter, databaseKey, random);
}
public Bucket createEncryptedBucketForClientLayer(Bucket underlying) {
return new AEADCryptBucket(underlying, getKeyForClientLayer());
}
public static DatabaseKey createRandom(RandomSource random) {
byte[] databaseKey = new byte[32];
random.nextBytes(databaseKey);
return new DatabaseKey(databaseKey, random);
}
/** Key Derivation Function for plugin stores: Use the database key as an HMAC key to an HMAC
* of the key plus some constant plus the storeIdentifier.
* @param storeIdentifier The classname of the plugin, used as part of a filename.
* @return An encryption key, as byte[].
*/
public byte[] getPluginStoreKey(String storeIdentifier) {
try {
byte[] id = storeIdentifier.getBytes("UTF-8");
byte[] full = new byte[databaseKey.length+PLUGIN.length+id.length];
int x = 0;
System.arraycopy(databaseKey, 0, full, 0, databaseKey.length);
x += databaseKey.length;
System.arraycopy(PLUGIN, 0, full, x, PLUGIN.length);
x += PLUGIN.length;
System.arraycopy(id, 0, full, x, id.length);
return HMAC.macWithSHA256(databaseKey, full, 32);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
/** Key Derivation Function for client.dat: Use the database key as an HMAC key to an HMAC
* of the key plus some constant plus the storeIdentifier.
* @return An encryption key, as byte[].
*/
public byte[] getKeyForClientLayer() {
byte[] full = new byte[databaseKey.length+CLIENT_LAYER.length];
int x = 0;
System.arraycopy(databaseKey, 0, full, 0, databaseKey.length);
x += databaseKey.length;
System.arraycopy(CLIENT_LAYER, 0, full, x, CLIENT_LAYER.length);
return HMAC.macWithSHA256(databaseKey, full, 32);
}
private static final byte[] PLUGIN;
private static final byte[] CLIENT_LAYER;
static {
try {
PLUGIN = "PLUGIN".getBytes("UTF-8");
CLIENT_LAYER = "CLIENT".getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + java.util.Arrays.hashCode(databaseKey);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
DatabaseKey other = (DatabaseKey) obj;
if (!java.util.Arrays.equals(databaseKey, other.databaseKey)) {
return false;
}
return true;
}
}