mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 12:49:55 +01:00
Improved encapsulation of thread synchronisation as follows
- replaced use of Object instance mutex with a private final Lock object - replaced Object signaling with specific condition signalling
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
package org.briarproject.crypto;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.briarproject.api.crypto.MessageDigest;
|
||||
import org.spongycastle.crypto.BlockCipher;
|
||||
import org.spongycastle.crypto.digests.SHA256Digest;
|
||||
@@ -23,61 +26,89 @@ class FortunaGenerator {
|
||||
private final byte[] counter = new byte[BLOCK_BYTES];
|
||||
private final byte[] buffer = new byte[BLOCK_BYTES];
|
||||
private final byte[] newKey = new byte[KEY_BYTES];
|
||||
|
||||
private final Lock synchLock = new ReentrantLock();
|
||||
|
||||
FortunaGenerator(byte[] seed) {
|
||||
reseed(seed);
|
||||
}
|
||||
|
||||
synchronized void reseed(byte[] seed) {
|
||||
digest.update(key);
|
||||
digest.update(seed);
|
||||
digest.digest(key, 0, KEY_BYTES);
|
||||
incrementCounter();
|
||||
void reseed(byte[] seed) {
|
||||
synchLock.lock();
|
||||
try{
|
||||
digest.update(key);
|
||||
digest.update(seed);
|
||||
digest.digest(key, 0, KEY_BYTES);
|
||||
incrementCounter();
|
||||
}
|
||||
finally{
|
||||
synchLock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Package access for testing
|
||||
synchronized void incrementCounter() {
|
||||
counter[0]++;
|
||||
for(int i = 0; counter[i] == 0; i++) {
|
||||
if(i + 1 == BLOCK_BYTES)
|
||||
throw new RuntimeException("Counter exhausted");
|
||||
counter[i + 1]++;
|
||||
void incrementCounter() {
|
||||
synchLock.lock();
|
||||
try{
|
||||
counter[0]++;
|
||||
for(int i = 0; counter[i] == 0; i++) {
|
||||
if(i + 1 == BLOCK_BYTES)
|
||||
throw new RuntimeException("Counter exhausted");
|
||||
counter[i + 1]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally{
|
||||
synchLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// Package access for testing
|
||||
synchronized byte[] getCounter() {
|
||||
return counter;
|
||||
byte[] getCounter() {
|
||||
synchLock.lock();
|
||||
try{
|
||||
return counter;
|
||||
}
|
||||
finally{
|
||||
synchLock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
synchronized int nextBytes(byte[] dest, int off, int len) {
|
||||
// Don't write more than the maximum number of bytes in one request
|
||||
if(len > MAX_BYTES_PER_REQUEST) len = MAX_BYTES_PER_REQUEST;
|
||||
cipher.init(true, new KeyParameter(key));
|
||||
// Generate full blocks directly into the output buffer
|
||||
int fullBlocks = len / BLOCK_BYTES;
|
||||
for(int i = 0; i < fullBlocks; i++) {
|
||||
cipher.processBlock(counter, 0, dest, off + i * BLOCK_BYTES);
|
||||
incrementCounter();
|
||||
int nextBytes(byte[] dest, int off, int len) {
|
||||
synchLock.lock();
|
||||
try{
|
||||
// Don't write more than the maximum number of bytes in one request
|
||||
if(len > MAX_BYTES_PER_REQUEST) len = MAX_BYTES_PER_REQUEST;
|
||||
cipher.init(true, new KeyParameter(key));
|
||||
// Generate full blocks directly into the output buffer
|
||||
int fullBlocks = len / BLOCK_BYTES;
|
||||
for(int i = 0; i < fullBlocks; i++) {
|
||||
cipher.processBlock(counter, 0, dest, off + i * BLOCK_BYTES);
|
||||
incrementCounter();
|
||||
}
|
||||
// Generate a partial block if needed
|
||||
int done = fullBlocks * BLOCK_BYTES, remaining = len - done;
|
||||
assert remaining < BLOCK_BYTES;
|
||||
if(remaining > 0) {
|
||||
cipher.processBlock(counter, 0, buffer, 0);
|
||||
incrementCounter();
|
||||
// Copy the partial block to the output buffer and erase our copy
|
||||
System.arraycopy(buffer, 0, dest, off + done, remaining);
|
||||
for(int i = 0; i < BLOCK_BYTES; i++) buffer[i] = 0;
|
||||
}
|
||||
// Generate a new key
|
||||
for(int i = 0; i < KEY_BYTES / BLOCK_BYTES; i++) {
|
||||
cipher.processBlock(counter, 0, newKey, i * BLOCK_BYTES);
|
||||
incrementCounter();
|
||||
}
|
||||
System.arraycopy(newKey, 0, key, 0, KEY_BYTES);
|
||||
for(int i = 0; i < KEY_BYTES; i++) newKey[i] = 0;
|
||||
// Return the number of bytes written
|
||||
return len;
|
||||
}
|
||||
// Generate a partial block if needed
|
||||
int done = fullBlocks * BLOCK_BYTES, remaining = len - done;
|
||||
assert remaining < BLOCK_BYTES;
|
||||
if(remaining > 0) {
|
||||
cipher.processBlock(counter, 0, buffer, 0);
|
||||
incrementCounter();
|
||||
// Copy the partial block to the output buffer and erase our copy
|
||||
System.arraycopy(buffer, 0, dest, off + done, remaining);
|
||||
for(int i = 0; i < BLOCK_BYTES; i++) buffer[i] = 0;
|
||||
finally{
|
||||
synchLock.unlock();
|
||||
}
|
||||
// Generate a new key
|
||||
for(int i = 0; i < KEY_BYTES / BLOCK_BYTES; i++) {
|
||||
cipher.processBlock(counter, 0, newKey, i * BLOCK_BYTES);
|
||||
incrementCounter();
|
||||
}
|
||||
System.arraycopy(newKey, 0, key, 0, KEY_BYTES);
|
||||
for(int i = 0; i < KEY_BYTES; i++) newKey[i] = 0;
|
||||
// Return the number of bytes written
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.briarproject.crypto;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.briarproject.api.crypto.MessageDigest;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.util.ByteUtils;
|
||||
@@ -10,6 +13,8 @@ class PseudoRandomImpl implements PseudoRandom {
|
||||
|
||||
private byte[] state;
|
||||
private int offset;
|
||||
|
||||
private final Lock synchLock = new ReentrantLock();
|
||||
|
||||
PseudoRandomImpl(MessageDigest messageDigest, int seed1, int seed2) {
|
||||
this.messageDigest = messageDigest;
|
||||
@@ -21,21 +26,27 @@ class PseudoRandomImpl implements PseudoRandom {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
public synchronized byte[] nextBytes(int bytes) {
|
||||
byte[] b = new byte[bytes];
|
||||
int half = state.length / 2;
|
||||
int off = 0, len = b.length, available = half - offset;
|
||||
while(available < len) {
|
||||
System.arraycopy(state, offset, b, off, available);
|
||||
off += available;
|
||||
len -= available;
|
||||
messageDigest.update(state, half, half);
|
||||
state = messageDigest.digest();
|
||||
offset = 0;
|
||||
available = half;
|
||||
public byte[] nextBytes(int bytes) {
|
||||
synchLock.lock();
|
||||
try{
|
||||
byte[] b = new byte[bytes];
|
||||
int half = state.length / 2;
|
||||
int off = 0, len = b.length, available = half - offset;
|
||||
while(available < len) {
|
||||
System.arraycopy(state, offset, b, off, available);
|
||||
off += available;
|
||||
len -= available;
|
||||
messageDigest.update(state, half, half);
|
||||
state = messageDigest.digest();
|
||||
offset = 0;
|
||||
available = half;
|
||||
}
|
||||
System.arraycopy(state, offset, b, off, len);
|
||||
offset += len;
|
||||
return b;
|
||||
}
|
||||
finally{
|
||||
synchLock.unlock();
|
||||
}
|
||||
System.arraycopy(state, offset, b, off, len);
|
||||
offset += len;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.briarproject.crypto;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
import org.briarproject.util.ByteUtils;
|
||||
|
||||
@@ -8,23 +11,38 @@ class SecretKeyImpl implements SecretKey {
|
||||
private final byte[] key;
|
||||
|
||||
private boolean erased = false; // Locking: this
|
||||
|
||||
private final Lock synchLock = new ReentrantLock();
|
||||
|
||||
SecretKeyImpl(byte[] key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public synchronized byte[] getEncoded() {
|
||||
if(erased) throw new IllegalStateException();
|
||||
return key;
|
||||
public byte[] getEncoded() {
|
||||
synchLock.lock();
|
||||
try{
|
||||
if(erased) throw new IllegalStateException();
|
||||
return key;
|
||||
}
|
||||
finally{
|
||||
synchLock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public SecretKey copy() {
|
||||
return new SecretKeyImpl(key.clone());
|
||||
}
|
||||
|
||||
public synchronized void erase() {
|
||||
if(erased) throw new IllegalStateException();
|
||||
ByteUtils.erase(key);
|
||||
erased = true;
|
||||
public void erase() {
|
||||
synchLock.lock();
|
||||
try{
|
||||
if(erased) throw new IllegalStateException();
|
||||
ByteUtils.erase(key);
|
||||
erased = true;
|
||||
}
|
||||
finally{
|
||||
synchLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user