Changeset 53dd0c7


Ignore:
Timestamp:
Oct 2, 2010 2:23:56 PM (10 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
c10a4f5
Parents:
6f449aa
Message:
  • Crypto:
    • Convert all ArrayList? caching to LBQs in YKGenerator, HMACGenerator, and AESKeyCache.
    • Change DSAEngine params from Hash to new SHA1Hash, since these were really 20 byte hashes, not 32 byte Hashes.
    • Add stats to track YKGenerator caching success
    • Fix YKGenerator precalculation to be much more useful by increasing the cache size and dramatically shortening the delay
    • Option cleanups
    • YKGenerator cleanups
    • Mark HMAC256Generator unused
Location:
core/java/src/net/i2p/crypto
Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • core/java/src/net/i2p/crypto/CryptixAESKeyCache.java

    r6f449aa r53dd0c7  
    11package net.i2p.crypto;
    22
    3 import java.util.ArrayList;
    4 import java.util.List;
     3import java.util.concurrent.LinkedBlockingQueue;
    54
    65/**
     
    1211 */
    1312public final class CryptixAESKeyCache {
    14     private final List _availableKeys;
     13    private final LinkedBlockingQueue<KeyCacheEntry> _availableKeys;
    1514   
    1615    private static final int KEYSIZE = 32; // 256bit AES
     
    2322   
    2423    public CryptixAESKeyCache() {
    25         _availableKeys = new ArrayList(MAX_KEYS);
     24        _availableKeys = new LinkedBlockingQueue(MAX_KEYS);
    2625    }
    2726   
     
    3130     */
    3231    public final KeyCacheEntry acquireKey() {
    33         synchronized (_availableKeys) {
    34             if (!_availableKeys.isEmpty())
    35                 return (KeyCacheEntry)_availableKeys.remove(0);
    36         }
     32        KeyCacheEntry rv = _availableKeys.poll();
     33        if (rv != null)
     34            return rv;
    3735        return createNew();
    3836    }
     
    4341     */
    4442    public final void releaseKey(KeyCacheEntry key) {
    45         synchronized (_availableKeys) {
    46             if (_availableKeys.size() < MAX_KEYS)
    47                 _availableKeys.add(key);
    48         }
     43        _availableKeys.offer(key);
    4944    }
    5045   
  • core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java

    r6f449aa r53dd0c7  
    6666    public final static String PROP_DH_PRECALC_MAX = "crypto.dh.precalc.max";
    6767    public final static String PROP_DH_PRECALC_DELAY = "crypto.dh.precalc.delay";
    68     public final static String DEFAULT_DH_PRECALC_MIN = "5";
    69     public final static String DEFAULT_DH_PRECALC_MAX = "50";
    70     public final static String DEFAULT_DH_PRECALC_DELAY = "10000";
     68    public final static int DEFAULT_DH_PRECALC_MIN = 5;
     69    public final static int DEFAULT_DH_PRECALC_MAX = 50;
     70    public final static int DEFAULT_DH_PRECALC_DELAY = 10000;
    7171
    7272    static {
     
    7474        ctx.statManager().createRateStat("crypto.dhGeneratePublicTime", "How long it takes to create x and X", "Encryption", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
    7575        ctx.statManager().createRateStat("crypto.dhCalculateSessionTime", "How long it takes to create the session key", "Encryption", new long[] { 60*1000, 5*60*1000, 60*60*1000 });       
    76         try {
    77             int val = Integer.parseInt(ctx.getProperty(PROP_DH_PRECALC_MIN, DEFAULT_DH_PRECALC_MIN));
    78             MIN_NUM_BUILDERS = val;
    79         } catch (Throwable t) {
    80             int val = Integer.parseInt(DEFAULT_DH_PRECALC_MIN);
    81             MIN_NUM_BUILDERS = val;
    82         }
    83         try {
    84             int val = Integer.parseInt(ctx.getProperty(PROP_DH_PRECALC_MAX, DEFAULT_DH_PRECALC_MAX));
    85             MAX_NUM_BUILDERS = val;
    86         } catch (Throwable t) {
    87             int val = Integer.parseInt(DEFAULT_DH_PRECALC_MAX);
    88             MAX_NUM_BUILDERS = val;
    89         }
    90         try {
    91             int val = Integer.parseInt(ctx.getProperty(PROP_DH_PRECALC_DELAY, DEFAULT_DH_PRECALC_DELAY));
    92             CALC_DELAY = val;
    93         } catch (Throwable t) {
    94             int val = Integer.parseInt(DEFAULT_DH_PRECALC_DELAY);
    95             CALC_DELAY = val;
    96         }
     76        MIN_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MIN, DEFAULT_DH_PRECALC_MIN);
     77        MAX_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MAX, DEFAULT_DH_PRECALC_MAX);
     78        CALC_DELAY = ctx.getProperty(PROP_DH_PRECALC_DELAY, DEFAULT_DH_PRECALC_DELAY);
    9779
    9880        if (_log.shouldLog(Log.DEBUG))
  • core/java/src/net/i2p/crypto/DSAEngine.java

    r6f449aa r53dd0c7  
    4242import net.i2p.util.NativeBigInteger;
    4343
     44/**
     45 *  Params and rv's changed from Hash to SHA1Hash for version 0.8.1
     46 *  There shouldn't be any external users of those variants.
     47 */
    4448public class DSAEngine {
    4549    private Log _log;
     
    6266        return verifySignature(signature, calculateHash(in), verifyingKey);
    6367    }
    64     public boolean verifySignature(Signature signature, Hash hash, SigningPublicKey verifyingKey) {
     68
     69    /** @param hash SHA-1 hash, NOT a SHA-256 hash */
     70    public boolean verifySignature(Signature signature, SHA1Hash hash, SigningPublicKey verifyingKey) {
    6571        long start = _context.clock().now();
    6672
     
    112118    public Signature sign(byte data[], int offset, int length, SigningPrivateKey signingKey) {
    113119        if ((signingKey == null) || (data == null) || (data.length <= 0)) return null;
    114         Hash h = calculateHash(data, offset, length);
     120        SHA1Hash h = calculateHash(data, offset, length);
    115121        return sign(h, signingKey);
    116122    }
     
    118124    public Signature sign(InputStream in, SigningPrivateKey signingKey) {
    119125        if ((signingKey == null) || (in == null) ) return null;
    120         Hash h = calculateHash(in);
     126        SHA1Hash h = calculateHash(in);
    121127        return sign(h, signingKey);
    122128    }
    123129
    124     public Signature sign(Hash hash, SigningPrivateKey signingKey) {
     130    /** @param hash SHA-1 hash, NOT a SHA-256 hash */
     131    public Signature sign(SHA1Hash hash, SigningPrivateKey signingKey) {
    125132        if ((signingKey == null) || (hash == null)) return null;
    126133        long start = _context.clock().now();
     
    187194    }
    188195   
    189     public Hash calculateHash(InputStream in) {
     196    /** @return hash SHA-1 hash, NOT a SHA-256 hash */
     197    public SHA1Hash calculateHash(InputStream in) {
    190198        SHA1 digest = new SHA1();
    191199        byte buf[] = new byte[64];
     
    200208            return null;
    201209        }
    202         return new Hash(digest.engineDigest());
    203     }
    204 
    205     public static Hash calculateHash(byte[] source, int offset, int len) {
     210        return new SHA1Hash(digest.engineDigest());
     211    }
     212
     213    /** @return hash SHA-1 hash, NOT a SHA-256 hash */
     214    public static SHA1Hash calculateHash(byte[] source, int offset, int len) {
    206215        SHA1 h = new SHA1();
    207216        h.engineUpdate(source, offset, len);
    208217        byte digested[] = h.digest();
    209         return new Hash(digested);
     218        return new SHA1Hash(digested);
    210219    }
    211220
  • core/java/src/net/i2p/crypto/HMAC256Generator.java

    r6f449aa r53dd0c7  
    1616 * {@link org.bouncycastle.crypto.digests.MD5Digest}.
    1717 *
     18 * deprecated unused
    1819 */
    1920public class HMAC256Generator extends HMACGenerator {
     
    2223    @Override
    2324    protected I2PHMac acquire() {
    24         synchronized (_available) {
    25             if (!_available.isEmpty())
    26                 return (I2PHMac)_available.remove(0);
    27         }
     25        I2PHMac rv = _available.poll();
     26        if (rv != null)
     27            return rv;
    2828        // the HMAC is hardcoded to use SHA256 digest size
    2929        // for backwards compatability.  next time we have a backwards
     
    4444    }
    4545   
     46/******
    4647    public static void main(String args[]) {
    4748        I2PAppContext ctx = I2PAppContext.getGlobalContext();
     
    5253        System.out.println(Base64.encode(mac.getData()));
    5354    }
     55******/
    5456}
  • core/java/src/net/i2p/crypto/HMACGenerator.java

    r6f449aa r53dd0c7  
    11package net.i2p.crypto;
    22
    3 import java.util.ArrayList;
    43import java.util.Arrays;
    5 import java.util.List;
     4import java.util.concurrent.LinkedBlockingQueue;
    65
    76import net.i2p.I2PAppContext;
     
    2322    private I2PAppContext _context;
    2423    /** set of available HMAC instances for calculate */
    25     protected final List _available;
     24    protected final LinkedBlockingQueue<I2PHMac> _available;
    2625    /** set of available byte[] buffers for verify */
    27     private final  List _availableTmp;
     26    private final LinkedBlockingQueue<byte[]> _availableTmp;
    2827   
    2928    public HMACGenerator(I2PAppContext context) {
    3029        _context = context;
    31         _available = new ArrayList(32);
    32         _availableTmp = new ArrayList(32);
     30        _available = new LinkedBlockingQueue(32);
     31        _availableTmp = new LinkedBlockingQueue(32);
    3332    }
    3433   
     
    8988   
    9089    protected I2PHMac acquire() {
    91         synchronized (_available) {
    92             if (!_available.isEmpty())
    93                 return (I2PHMac)_available.remove(0);
    94         }
     90        I2PHMac rv = _available.poll();
     91        if (rv != null)
     92            return rv;
    9593        // the HMAC is hardcoded to use SHA256 digest size
    9694        // for backwards compatability.  next time we have a backwards
     
    9896        return new I2PHMac(new MD5Digest(), 32);
    9997    }
    100     private void release(Mac mac) {
    101         synchronized (_available) {
    102             if (_available.size() < 64)
    103                 _available.add(mac);
    104         }
     98
     99    private void release(I2PHMac mac) {
     100        _available.offer(mac);
    105101    }
    106102
    107103    // temp buffers for verify(..)
    108104    private byte[] acquireTmp() {
    109         byte rv[] = null;
    110         synchronized (_availableTmp) {
    111             if (!_availableTmp.isEmpty())
    112                 rv = (byte[])_availableTmp.remove(0);
    113         }
     105        byte rv[] = _availableTmp.poll();
    114106        if (rv != null)
    115107            Arrays.fill(rv, (byte)0x0);
     
    118110        return rv;
    119111    }
     112
    120113    private void releaseTmp(byte tmp[]) {
    121         synchronized (_availableTmp) {
    122             if (_availableTmp.size() < 64)
    123                 _availableTmp.add((Object)tmp);
    124         }
     114        _availableTmp.offer(tmp);
    125115    }
    126116}
  • core/java/src/net/i2p/crypto/SHA1.java

    r6f449aa r53dd0c7  
    6464     * This implementation returns a fixed-size digest.
    6565     */
    66     private static final int HASH_LENGTH = 20; // bytes == 160 bits
     66    static final int HASH_LENGTH = 20; // bytes == 160 bits
    6767 
    6868    /**
  • core/java/src/net/i2p/crypto/YKGenerator.java

    r6f449aa r53dd0c7  
    1111
    1212import java.math.BigInteger;
    13 import java.util.ArrayList;
    14 import java.util.List;
     13import java.util.concurrent.LinkedBlockingQueue;
    1514
    1615import net.i2p.I2PAppContext;
     
    1918import net.i2p.util.Log;
    2019import net.i2p.util.NativeBigInteger;
    21 import net.i2p.util.RandomSource;
    2220
    2321/**
     
    2624 * This class precalcs a set of values on its own thread, using those transparently
    2725 * when a new instance is created.  By default, the minimum threshold for creating
    28  * new values for the pool is 5, and the max pool size is 10.  Whenever the pool has
     26 * new values for the pool is 20, and the max pool size is 50.  Whenever the pool has
    2927 * less than the minimum, it fills it up again to the max.  There is a delay after
    30  * each precalculation so that the CPU isn't hosed during startup (defaulting to 10 seconds). 
     28 * each precalculation so that the CPU isn't hosed during startup.
    3129 * These three parameters are controlled by java environmental variables and
    3230 * can be adjusted via:
     
    4038 */
    4139class YKGenerator {
    42     private final static Log _log = new Log(YKGenerator.class);
    43     private static int MIN_NUM_BUILDERS = -1;
    44     private static int MAX_NUM_BUILDERS = -1;
    45     private static int CALC_DELAY = -1;
    46     /* FIXME final type if you are to syncronize FIXME */
    47     private static volatile List _values = new ArrayList(50); // list of BigInteger[] values (y and k)
    48     private static Thread _precalcThread = null;
     40    //private final static Log _log = new Log(YKGenerator.class);
     41    private static final int MIN_NUM_BUILDERS;
     42    private static final int MAX_NUM_BUILDERS;
     43    private static final int CALC_DELAY;
     44    private static final LinkedBlockingQueue<BigInteger[]> _values = new LinkedBlockingQueue(50); // list of BigInteger[] values (y and k)
     45    private static final Thread _precalcThread;
     46    private static final I2PAppContext ctx;
    4947
    5048    public final static String PROP_YK_PRECALC_MIN = "crypto.yk.precalc.min";
    5149    public final static String PROP_YK_PRECALC_MAX = "crypto.yk.precalc.max";
    5250    public final static String PROP_YK_PRECALC_DELAY = "crypto.yk.precalc.delay";
    53     public final static String DEFAULT_YK_PRECALC_MIN = "10";
    54     public final static String DEFAULT_YK_PRECALC_MAX = "30";
    55     public final static String DEFAULT_YK_PRECALC_DELAY = "10000";
     51    public final static int DEFAULT_YK_PRECALC_MIN = 20;
     52    public final static int DEFAULT_YK_PRECALC_MAX = 50;
     53    public final static int DEFAULT_YK_PRECALC_DELAY = 200;
    5654
    5755    /** check every 30 seconds whether we have less than the minimum */
    58     private final static long CHECK_DELAY = 30 * 1000;
     56    private static long CHECK_DELAY = 30 * 1000;
    5957
    6058    static {
    61         I2PAppContext ctx = I2PAppContext.getGlobalContext();
    62         try {
    63             int val = Integer.parseInt(ctx.getProperty(PROP_YK_PRECALC_MIN, DEFAULT_YK_PRECALC_MIN));
    64             MIN_NUM_BUILDERS = val;
    65         } catch (Throwable t) {
    66             int val = Integer.parseInt(DEFAULT_YK_PRECALC_MIN);
    67             MIN_NUM_BUILDERS = val;
    68         }
    69         try {
    70             int val = Integer.parseInt(ctx.getProperty(PROP_YK_PRECALC_MAX, DEFAULT_YK_PRECALC_MAX));
    71             MAX_NUM_BUILDERS = val;
    72         } catch (Throwable t) {
    73             int val = Integer.parseInt(DEFAULT_YK_PRECALC_MAX);
    74             MAX_NUM_BUILDERS = val;
    75         }
    76         try {
    77             int val = Integer.parseInt(ctx.getProperty(PROP_YK_PRECALC_DELAY, DEFAULT_YK_PRECALC_DELAY));
    78             CALC_DELAY = val;
    79         } catch (Throwable t) {
    80             int val = Integer.parseInt(DEFAULT_YK_PRECALC_DELAY);
    81             CALC_DELAY = val;
    82         }
     59        ctx = I2PAppContext.getGlobalContext();
     60        MIN_NUM_BUILDERS = ctx.getProperty(PROP_YK_PRECALC_MIN, DEFAULT_YK_PRECALC_MIN);
     61        MAX_NUM_BUILDERS = ctx.getProperty(PROP_YK_PRECALC_MAX, DEFAULT_YK_PRECALC_MAX);
     62        CALC_DELAY = ctx.getProperty(PROP_YK_PRECALC_DELAY, DEFAULT_YK_PRECALC_DELAY);
    8363
    84         if (_log.shouldLog(Log.DEBUG))
    85             _log.debug("ElGamal YK Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
    86                        + CALC_DELAY + ")");
     64        //if (_log.shouldLog(Log.DEBUG))
     65        //    _log.debug("ElGamal YK Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
     66        //               + CALC_DELAY + ")");
     67
     68        ctx.statManager().createRateStat("crypto.YKUsed", "Need a YK from the queue", "Encryption", new long[] { 60*60*1000 });
     69        ctx.statManager().createRateStat("crypto.YKEmpty", "YK queue empty", "Encryption", new long[] { 60*60*1000 });
    8770
    8871        _precalcThread = new I2PThread(new YKPrecalcRunner(MIN_NUM_BUILDERS, MAX_NUM_BUILDERS));
     
    9477
    9578    private static final int getSize() {
    96         synchronized (_values) {
    97             return _values.size();
    98         }
     79        return _values.size();
    9980    }
    10081
    101     private static final int addValues(BigInteger yk[]) {
    102         int sz = 0;
    103         synchronized (_values) {
    104             _values.add(yk);
    105             sz = _values.size();
    106         }
    107         return sz;
     82    /** @return true if successful, false if full */
     83    private static final boolean addValues(BigInteger yk[]) {
     84        return _values.offer(yk);
    10885    }
    10986
     87    /** @return rv[0] = Y; rv[1] = K */
    11088    public static BigInteger[] getNextYK() {
    111         if (true) {
    112             synchronized (_values) {
    113                 if (!_values.isEmpty()) {
    114                     if (_log.shouldLog(Log.DEBUG))
    115                         _log.debug("Sufficient precalculated YK values - fetch the existing");
    116                     return (BigInteger[]) _values.remove(0);
    117                 }
    118             }
    119         }
    120         if (_log.shouldLog(Log.INFO)) _log.info("Insufficient precalculated YK values - create a new one");
     89        ctx.statManager().addRateData("crypto.YKUsed", 1, 0);
     90        BigInteger[] rv = _values.poll();
     91        if (rv != null)
     92            return rv;
     93        ctx.statManager().addRateData("crypto.YKEmpty", 1, 0);
    12194        return generateYK();
    12295    }
     
    12497    private final static BigInteger _two = new NativeBigInteger(1, new byte[] { 0x02});
    12598
     99    /** @return rv[0] = Y; rv[1] = K */
    126100    private static final BigInteger[] generateYK() {
    127101        NativeBigInteger k = null;
    128102        BigInteger y = null;
    129         long t0 = 0;
    130         long t1 = 0;
     103        //long t0 = 0;
     104        //long t1 = 0;
    131105        while (k == null) {
    132             t0 = Clock.getInstance().now();
    133             k = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, RandomSource.getInstance());
    134             t1 = Clock.getInstance().now();
     106            //t0 = Clock.getInstance().now();
     107            k = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, ctx.random());
     108            //t1 = Clock.getInstance().now();
    135109            if (BigInteger.ZERO.compareTo(k) == 0) {
    136110                k = null;
     
    140114            if (kPlus2.compareTo(CryptoConstants.elgp) > 0) k = null;
    141115        }
    142         long t2 = Clock.getInstance().now();
     116        //long t2 = Clock.getInstance().now();
    143117        y = CryptoConstants.elgg.modPow(k, CryptoConstants.elgp);
    144118
     
    147121        yk[1] = k;
    148122
    149         long diff = t2 - t0;
    150         if (diff > 1000) {
    151             if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to generate YK value for ElGamal (" + diff + "ms)");
    152         }
     123        //long diff = t2 - t0;
     124        //if (diff > 1000) {
     125        //    if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to generate YK value for ElGamal (" + diff + "ms)");
     126        //}
    153127
    154128        return yk;
     
    156130
    157131    public static void main(String args[]) {
    158         RandomSource.getInstance().nextBoolean(); // warm it up
    159         try {
    160             Thread.sleep(20 * 1000);
    161         } catch (InterruptedException ie) { // nop
    162         }
    163         _log.debug("\n\n\n\nBegin test\n");
     132        System.out.println("\n\n\n\nBegin test\n");
    164133        long negTime = 0;
    165134        for (int i = 0; i < 5; i++) {
     
    167136            getNextYK();
    168137            long endNeg = Clock.getInstance().now();
     138            negTime += endNeg - startNeg;
    169139        }
    170         _log.debug("YK fetch time for 5 runs: " + negTime + " @ " + negTime / 5l + "ms each");
    171         try {
    172             Thread.sleep(30 * 1000);
    173         } catch (InterruptedException ie) { // nop
    174         }
     140        System.out.println("YK fetch time for 5 runs: " + negTime + " @ " + negTime / 5l + "ms each");
    175141    }
    176142
     
    187153            while (true) {
    188154                int curSize = 0;
    189                 long start = Clock.getInstance().now();
     155                //long start = Clock.getInstance().now();
    190156                int startSize = getSize();
     157                // Adjust delay
     158                if (startSize <= (_minSize / 2) && CHECK_DELAY > 1000)
     159                    CHECK_DELAY -= 1000;
     160                else if (startSize > (_minSize * 2) && CHECK_DELAY < 60000)
     161                         CHECK_DELAY += 1000;
    191162                curSize = startSize;
    192                 while (curSize < _minSize) {
    193                     while (curSize < _maxSize) {
    194                         long begin = Clock.getInstance().now();
    195                         curSize = addValues(generateYK());
    196                         long end = Clock.getInstance().now();
    197                         if (_log.shouldLog(Log.DEBUG)) _log.debug("Precalculated YK value in " + (end - begin) + "ms");
     163                if (curSize < _minSize) {
     164                    for (int i = curSize; i < _maxSize; i++) {
     165                        //long begin = Clock.getInstance().now();
     166                        if (!addValues(generateYK()))
     167                            break;
     168                        //long end = Clock.getInstance().now();
     169                        //if (_log.shouldLog(Log.DEBUG)) _log.debug("Precalculated YK value in " + (end - begin) + "ms");
    198170                        // for some relief...
    199171                        try {
     
    203175                    }
    204176                }
    205                 long end = Clock.getInstance().now();
    206                 int numCalc = curSize - startSize;
    207                 if (numCalc > 0) {
    208                     if (_log.shouldLog(Log.DEBUG))
    209                         _log.debug("Precalced " + numCalc + " to " + curSize + " in "
    210                                    + (end - start - CALC_DELAY * numCalc) + "ms (not counting "
    211                                    + (CALC_DELAY * numCalc) + "ms relief).  now sleeping");
    212                 }
     177                //long end = Clock.getInstance().now();
     178                //int numCalc = curSize - startSize;
     179                //if (numCalc > 0) {
     180                //    if (_log.shouldLog(Log.DEBUG))
     181                //        _log.debug("Precalced " + numCalc + " to " + curSize + " in "
     182                //                   + (end - start - CALC_DELAY * numCalc) + "ms (not counting "
     183                //                   + (CALC_DELAY * numCalc) + "ms relief).  now sleeping");
     184                //}
    213185                try {
    214186                    Thread.sleep(CHECK_DELAY);
Note: See TracChangeset for help on using the changeset viewer.