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);
        }

        /**


Reply via email to