[freenet-cvs] r20989 - branches/saltedhashstore/freenet/src/freenet/store/saltedhash

j16sdiz at freenetproject.org j16sdiz at freenetproject.org
Fri Jul 4 13:53:29 UTC 2008


Author: j16sdiz
Date: 2008-07-04 13:53:29 +0000 (Fri, 04 Jul 2008)
New Revision: 20989

Added:
   branches/saltedhashstore/freenet/src/freenet/store/saltedhash/CipherManager.java
Modified:
   branches/saltedhashstore/freenet/src/freenet/store/saltedhash/SaltedHashFreenetStore.java
Log:
factor out CipherManager

Added: branches/saltedhashstore/freenet/src/freenet/store/saltedhash/CipherManager.java
===================================================================
--- branches/saltedhashstore/freenet/src/freenet/store/saltedhash/CipherManager.java	                        (rev 0)
+++ branches/saltedhashstore/freenet/src/freenet/store/saltedhash/CipherManager.java	2008-07-04 13:53:29 UTC (rev 20989)
@@ -0,0 +1,163 @@
+/* This code is part of Freenet. It is distributed under the GNU General
+ * Public License, version 2 (or at your option any later version). See
+ * http://www.gnu.org/ for further details of the GPL. */
+package freenet.store.saltedhash;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Random;
+
+import freenet.crypt.BlockCipher;
+import freenet.crypt.PCFBMode;
+import freenet.crypt.SHA256;
+import freenet.crypt.UnsupportedCipherException;
+import freenet.crypt.ciphers.Rijndael;
+import freenet.support.ByteArrayWrapper;
+import freenet.support.Logger;
+
+/**
+ * Cipher Manager
+ * 
+ * Manage all kind of digestion and encryption in store
+ * 
+ * @author sdiz
+ */
+public class CipherManager {
+	/**
+	 * <tt>0x10</tt> bytes of salt for better digestion, not too salty.
+	 */
+	private byte[] salt;
+
+	CipherManager(byte[] salt) {
+		assert salt.length == 0x10;
+		this.salt = salt;
+	}
+
+	/**
+	 * Get salt
+	 * 
+	 * @return salt
+	 */
+	byte[] getSalt() {
+		return salt;
+	}
+
+	/**
+	 * Cache for digested keys
+	 */
+	private Map<ByteArrayWrapper, byte[]> digestRoutingKeyCache = new LinkedHashMap<ByteArrayWrapper, byte[]>() {
+		@Override
+		protected boolean removeEldestEntry(Map.Entry<ByteArrayWrapper, byte[]> eldest) {
+			return size() > 128;
+		}
+	};
+
+	/**
+	 * Get digested routing key
+	 * 
+	 * @param plainKey
+	 * @return
+	 */
+	byte[] getDigestedKey(byte[] plainKey) {
+		ByteArrayWrapper key = new ByteArrayWrapper(plainKey);
+		synchronized (digestRoutingKeyCache) {
+			byte[] dk = digestRoutingKeyCache.get(key);
+			if (dk != null)
+				return dk;
+		}
+
+		MessageDigest digest = SHA256.getMessageDigest();
+		try {
+			digest.update(plainKey);
+			digest.update(salt);
+
+			byte[] hashedRoutingKey = digest.digest();
+			assert hashedRoutingKey.length == 0x20;
+
+			synchronized (digestRoutingKeyCache) {
+				digestRoutingKeyCache.put(key, hashedRoutingKey);
+			}
+
+			return hashedRoutingKey;
+		} finally {
+			SHA256.returnMessageDigest(digest);
+		}
+	}
+
+	/**
+	 * Encrypt this entry
+	 */
+	void encrypt(SaltedHashFreenetStore.Entry entry, Random random) {
+		if (entry.isEncrypted)
+			return;
+
+		entry.dataEncryptIV = new byte[16];
+		random.nextBytes(entry.dataEncryptIV);
+
+		PCFBMode cipher = makeCipher(entry.dataEncryptIV, entry.plainRoutingKey);
+		entry.header = cipher.blockEncipher(entry.header, 0, entry.header.length);
+		entry.data = cipher.blockEncipher(entry.data, 0, entry.data.length);
+
+		entry.getDigestedRoutingKey();
+		entry.isEncrypted = true;
+	}
+
+	/**
+	 * Verify and decrypt this entry
+	 * 
+	 * @param routingKey
+	 * @return <code>true</code> if the <code>routeKey</code> match and the entry is decrypted.
+	 */
+	boolean decrypt(SaltedHashFreenetStore.Entry entry, byte[] routingKey) {
+		if (!entry.isEncrypted) {
+			// Already decrypted
+			if (Arrays.equals(entry.plainRoutingKey, routingKey))
+				return true;
+			else
+				return false;
+		}
+
+		if (entry.plainRoutingKey != null) {
+			// we knew the key
+			if (!Arrays.equals(entry.plainRoutingKey, routingKey)) {
+				return false;
+			}
+		} else {
+			// we do not know the plain key, let's check the digest
+			if (!Arrays.equals(entry.digestedRoutingKey, getDigestedKey(routingKey)))
+				return false;
+		}
+
+		entry.plainRoutingKey = routingKey;
+
+		PCFBMode cipher = makeCipher(entry.dataEncryptIV, entry.plainRoutingKey);
+		entry.header = cipher.blockDecipher(entry.header, 0, entry.header.length);
+		entry.data = cipher.blockDecipher(entry.data, 0, entry.data.length);
+
+		entry.isEncrypted = false;
+
+		return true;
+	}
+
+	/**
+	 * Create PCFBMode object for this key
+	 */
+	PCFBMode makeCipher(byte[] iv, byte[] key) {
+		byte[] iv2 = new byte[0x20]; // 256 bits
+
+		System.arraycopy(salt, 0, iv2, 0, 0x10);
+		System.arraycopy(iv, 0, iv2, 0x10, 0x10);
+
+		try {
+			BlockCipher aes = new Rijndael(256, 256);
+			aes.initialize(key);
+
+			return PCFBMode.create(aes, iv2);
+		} catch (UnsupportedCipherException e) {
+			Logger.error(this, "Rijndael not supported!", e);
+			throw new Error("Rijndael not supported!", e);
+		}
+	}
+}

Modified: branches/saltedhashstore/freenet/src/freenet/store/saltedhash/SaltedHashFreenetStore.java
===================================================================
--- branches/saltedhashstore/freenet/src/freenet/store/saltedhash/SaltedHashFreenetStore.java	2008-07-04 13:53:05 UTC (rev 20988)
+++ branches/saltedhashstore/freenet/src/freenet/store/saltedhash/SaltedHashFreenetStore.java	2008-07-04 13:53:29 UTC (rev 20989)
@@ -9,14 +9,11 @@
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
-import java.security.MessageDigest;
 import java.text.DecimalFormat;
 import java.util.Arrays;
-import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
-import java.util.Map;
 import java.util.Random;
 import java.util.Set;
 import java.util.SortedSet;
@@ -31,11 +28,6 @@
 
 import org.tanukisoftware.wrapper.WrapperManager;
 
-import freenet.crypt.BlockCipher;
-import freenet.crypt.PCFBMode;
-import freenet.crypt.SHA256;
-import freenet.crypt.UnsupportedCipherException;
-import freenet.crypt.ciphers.Rijndael;
 import freenet.keys.KeyVerifyException;
 import freenet.node.SemiOrderedShutdownHook;
 import freenet.store.FreenetStore;
@@ -43,7 +35,6 @@
 import freenet.store.StorableBlock;
 import freenet.store.StoreCallback;
 import freenet.support.BloomFilter;
-import freenet.support.ByteArrayWrapper;
 import freenet.support.Fields;
 import freenet.support.HexUtil;
 import freenet.support.Logger;
@@ -195,7 +186,7 @@
 	 */
 	private Entry probeEntry(byte[] routingKey) throws IOException {
 		if (checkBloom)
-			if (!bloomFilter.checkFilter(getDigestedRoutingKey(routingKey)))
+			if (!bloomFilter.checkFilter(cipherManager.getDigestedKey(routingKey)))
 				return null;
 
 		Entry entry = probeEntry0(routingKey, storeSize);
@@ -279,7 +270,7 @@
 						if (logDEBUG)
 							Logger.debug(this, "probing, write to i=" + i + ", offset=" + offset[i]);
 						if (updateBloom)
-							bloomFilter.updateFilter(getDigestedRoutingKey(routingKey));
+							bloomFilter.updateFilter(cipherManager.getDigestedKey(routingKey));
 						writeEntry(entry, offset[i]);
 						writes.incrementAndGet();
 						keyCount.incrementAndGet();
@@ -292,7 +283,7 @@
 				if (logDEBUG)
 					Logger.debug(this, "collision, write to i=0, offset=" + offset[0]);
 				if (updateBloom)
-					bloomFilter.updateFilter(getDigestedRoutingKey(routingKey));
+					bloomFilter.updateFilter(cipherManager.getDigestedKey(routingKey));
 				oldEntry = readEntry(offset[0], null);
 				writeEntry(entry, offset[0]);
 				writes.incrementAndGet();
@@ -355,17 +346,17 @@
 	 * Total length is padded to multiple of 512bytes. All reserved bytes should be zero when
 	 * written, ignored on read.
 	 */
-	private class Entry {
-		private byte[] plainRoutingKey;
-		private byte[] digestedRoutingKey;
-		private byte[] dataEncryptIV;
+	 class Entry {
+		byte[] plainRoutingKey;
+		byte[] digestedRoutingKey;
+		byte[] dataEncryptIV;
 		private long flag;
 		private long storeSize;
 		private byte generation;
-		private byte[] header;
-		private byte[] data;
+		byte[] header;
+		byte[] data;
 		
-		private boolean isEncrypted;
+		boolean isEncrypted;
 		public long curOffset = -1;
 		
 
@@ -451,7 +442,7 @@
 
 		public ByteBuffer toByteBuffer() {
 			ByteBuffer out = ByteBuffer.allocate((int) entryTotalLength);
-			encrypt();
+			cipherManager.encrypt(this, random);
 			out.put(getDigestedRoutingKey());
 			out.put(dataEncryptIV);
 
@@ -480,7 +471,7 @@
 		public StorableBlock getStorableBlock(byte[] routingKey, byte[] fullKey) throws KeyVerifyException {
 			if ((flag & ENTRY_FLAG_OCCUPIED) == 0)
 				return null; // this is a free block
-			if (!decrypt(routingKey))
+			if (!cipherManager.decrypt(this, routingKey))
 				return null;
 
 			StorableBlock block = callback.construct(data, header, routingKey, fullKey);
@@ -502,89 +493,13 @@
 				return getOffsetFromPlainKey(plainRoutingKey, storeSize);
 		}
 
-		/**
-		 * Verify and decrypt this entry
-		 *
-		 * @param routingKey
-		 * @return <code>true</code> if the <code>routeKey</code> match and the entry is decrypted.
-		 */
-		private boolean decrypt(byte[] routingKey) {
-			if (!isEncrypted) {
-				// Already decrypted
-				if (Arrays.equals(this.plainRoutingKey, routingKey))
-					return true;
-				else
-					return false;
-			}
-
-			if (plainRoutingKey != null) {
-				// we knew the key
-				if (!Arrays.equals(this.plainRoutingKey, routingKey)) {
-					return false;
-				}
-			} else {
-				// we do not know the plain key, let's check the digest
-				if (!Arrays.equals(this.digestedRoutingKey, SaltedHashFreenetStore.this
-				        .getDigestedRoutingKey(routingKey)))
-					return false;
-			}
-
-			this.plainRoutingKey = routingKey;
-
-			PCFBMode cipher = makeCipher(plainRoutingKey);
-			header = cipher.blockDecipher(header, 0, header.length);
-			data = cipher.blockDecipher(data, 0, data.length);
-
-			isEncrypted = false;
-
-			return true;
-		}
-
-		/**
-		 * Encrypt this entry
-		 */
-		private void encrypt() {
-			if (isEncrypted)
-				return;
-
-			dataEncryptIV = new byte[16];
-			random.nextBytes(dataEncryptIV);
-
-			PCFBMode cipher = makeCipher(plainRoutingKey);
-			header = cipher.blockEncipher(header, 0, header.length);
-			data = cipher.blockEncipher(data, 0, data.length);
-
-			getDigestedRoutingKey();
-			isEncrypted = true;
-		}
-
-		/**
-		 * Create Cipher
-		 */
-		private PCFBMode makeCipher(byte[] routingKey) {
-			byte[] iv = new byte[0x20]; // 256 bits
-
-			System.arraycopy(salt, 0, iv, 0, 0x10);
-			System.arraycopy(dataEncryptIV, 0, iv, 0x10, 0x10);
-
-			try {
-				BlockCipher aes = new Rijndael(256, 256);
-				aes.initialize(routingKey);
-
-				return PCFBMode.create(aes, iv);
-			} catch (UnsupportedCipherException e) {
-				Logger.error(this, "Rijndael not supported!", e);
-				throw new RuntimeException(e);
-			}
-		}
-
 		public boolean isFree() {
 			return (flag & ENTRY_FLAG_OCCUPIED) == 0;
 		}
 
 		public byte[] getDigestedRoutingKey() {
 			if (digestedRoutingKey == null)
-				digestedRoutingKey = SaltedHashFreenetStore.this.getDigestedRoutingKey(this.plainRoutingKey);
+				digestedRoutingKey = cipherManager.getDigestedKey(plainRoutingKey);
 			return digestedRoutingKey;
 		}
 
@@ -656,7 +571,7 @@
 		Entry entry = new Entry(bf);
 
 		if (routingKey != null) {
-			boolean decrypted = entry.decrypt(routingKey);
+			boolean decrypted = cipherManager.decrypt(entry, routingKey);
 			if (!decrypted)
 				return null;
 		}
@@ -675,7 +590,7 @@
 	 * </ul>
 	 */
 	private void writeEntry(Entry entry, long offset) throws IOException {
-		entry.encrypt();
+		cipherManager.encrypt(entry, random);
 
 		int split = (int) (offset % FILE_SPLIT);
 		long rawOffset = (offset / FILE_SPLIT) * entryTotalLength;
@@ -816,19 +731,21 @@
 	 * Load config file
 	 */
 	private void loadConfigFile() throws IOException {
-		assert salt == null; // never load the configuration twice
+		assert cipherManager == null; // never load the configuration twice
 
 		if (!configFile.exists()) {
 			// create new
-			salt = new byte[0x10];
-			random.nextBytes(salt);
+			byte[] newsalt = new byte[0x10];
+			random.nextBytes(newsalt);
+			cipherManager = new CipherManager(newsalt);
 
 			writeConfigFile();
 		} else {
 			// try to load
 			RandomAccessFile raf = new RandomAccessFile(configFile, "r");
-			salt = new byte[0x10];
+			byte[] salt = new byte[0x10];
 			raf.readFully(salt);
+			cipherManager = new CipherManager(salt);
 
 			storeSize = raf.readLong();
 			prevStoreSize = raf.readLong();
@@ -853,7 +770,7 @@
 			File tempConfig = new File(configFile.getPath() + ".tmp");
 			RandomAccessFile raf = new RandomAccessFile(tempConfig, "rw");
 			raf.seek(0);
-			raf.write(salt);
+			raf.write(cipherManager.getSalt());
 
 			raf.writeLong(storeSize);
 			raf.writeLong(prevStoreSize);
@@ -1355,11 +1272,11 @@
 	 * @return <code>true</code> if all the offsets are locked.
 	 */
 	private boolean lockPlainKey(byte[] plainKey, boolean usePrevStoreSize) {
-		return lockDigestedKey(getDigestedRoutingKey(plainKey), usePrevStoreSize);
+		return lockDigestedKey(cipherManager.getDigestedKey(plainKey), usePrevStoreSize);
 	}
 
 	private void unlockPlainKey(byte[] plainKey, boolean usePrevStoreSize) {
-		unlockDigestedKey(getDigestedRoutingKey(plainKey), usePrevStoreSize);
+		unlockDigestedKey(cipherManager.getDigestedKey(plainKey), usePrevStoreSize);
 	}
 
 	/**
@@ -1439,50 +1356,9 @@
 	}
 
 	// ------------- Hashing
-	/**
-	 * <tt>0x10</tt> bytes of salt for better digestion, not too salty.
-	 */
-	private byte[] salt;
-
-	private Map<ByteArrayWrapper, byte[]> digestRoutingKeyCache = new LinkedHashMap<ByteArrayWrapper, byte[]>() {
-		@Override
-		protected boolean removeEldestEntry(Map.Entry<ByteArrayWrapper, byte[]> eldest) {
-			return size() > 128;
-		}
-	};
+	private CipherManager cipherManager;
 	
-	/**
-	 * Get hashed routing key
-	 *
-	 * @param routingKey
-	 * @return
-	 */
-	private byte[] getDigestedRoutingKey(byte[] routingKey) {
-		ByteArrayWrapper key = new ByteArrayWrapper(routingKey);
-		synchronized (digestRoutingKeyCache) {
-			byte[] dk = digestRoutingKeyCache.get(key);
-			if (dk != null)
-				return dk;
-		}
-		
-		MessageDigest digest = SHA256.getMessageDigest();
-		try {
-			digest.update(routingKey);
-			digest.update(salt);
 
-			byte[] hashedRoutingKey = digest.digest();
-			assert hashedRoutingKey.length == 0x20;
-
-			synchronized (digestRoutingKeyCache) {
-				digestRoutingKeyCache.put(key, hashedRoutingKey);
-			}
-			
-			return hashedRoutingKey;
-		} finally {
-			SHA256.returnMessageDigest(digest);
-		}
-	}
-
 	/**
 	 * Get offset in the hash table, given a plain routing key.
 	 *
@@ -1491,7 +1367,7 @@
 	 * @return
 	 */
 	private long[] getOffsetFromPlainKey(byte[] plainKey, long storeSize) {
-		return getOffsetFromDigestedKey(getDigestedRoutingKey(plainKey), storeSize);
+		return getOffsetFromDigestedKey(cipherManager.getDigestedKey(plainKey), storeSize);
 	}
 
 	/**




More information about the cvs mailing list