Files
briar/components/net/sf/briar/transport/ConnectionEncrypterImpl.java

74 lines
1.9 KiB
Java

package net.sf.briar.transport;
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
import java.io.IOException;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import net.sf.briar.api.crypto.ErasableKey;
class ConnectionEncrypterImpl implements ConnectionEncrypter {
private final OutputStream out;
private final Cipher frameCipher;
private final ErasableKey frameKey;
private final byte[] iv, tag;
private long capacity, frame = 0L;
private boolean tagWritten = false;
ConnectionEncrypterImpl(OutputStream out, long capacity, Cipher tagCipher,
Cipher frameCipher, ErasableKey tagKey, ErasableKey frameKey) {
this.out = out;
this.capacity = capacity;
this.frameCipher = frameCipher;
this.frameKey = frameKey;
iv = IvEncoder.encodeIv(0, frameCipher.getBlockSize());
// Encrypt the tag
tag = TagEncoder.encodeTag(0, tagCipher, tagKey);
tagKey.erase();
}
public void writeFrame(byte[] b, int len) throws IOException {
if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
if(!tagWritten) {
try {
out.write(tag);
} catch(IOException e) {
frameKey.erase();
throw e;
}
capacity -= tag.length;
tagWritten = true;
}
IvEncoder.updateIv(iv, frame);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
try {
frameCipher.init(Cipher.ENCRYPT_MODE, frameKey, ivSpec);
int encrypted = frameCipher.doFinal(b, 0, len, b);
if(encrypted != len) throw new RuntimeException();
} catch(GeneralSecurityException badCipher) {
throw new RuntimeException(badCipher);
}
try {
out.write(b, 0, len);
} catch(IOException e) {
frameKey.erase();
throw e;
}
capacity -= len;
frame++;
}
public void flush() throws IOException {
out.flush();
}
public long getRemainingCapacity() {
return capacity;
}
}