package net.i2p.crypto; /* * free (adj.): unencumbered; not under the control of others * Written by jrandom in 2003 and released into the public domain * with no warranty of any kind, either expressed or implied. * It probably won't make your computer catch on fire, or eat * your children, but it might. Use at your own risk. * */ import net.i2p.I2PAppContext; import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.SessionKey; import net.i2p.util.Log; import net.i2p.util.SimpleByteCache; /** * Dummy wrapper for AES cipher operation. * Warning - * most methods UNUSED unless i2p.encryption = off * See CryptixAESEngine overrides for the real thing. */ public class AESEngine { protected final Log _log; protected final I2PAppContext _context; public AESEngine(I2PAppContext ctx) { _context = ctx; _log = _context.logManager().getLog(getClass()); if (getClass().equals(AESEngine.class)) _log.logAlways(Log.WARN, "AES is disabled"); } /** Encrypt the payload with the session key * @param payload data to be encrypted * @param payloadIndex index into the payload to start encrypting * @param out where to store the result * @param outIndex where in out to start writing * @param sessionKey private esession key to encrypt to * @param iv IV for CBC, must be 16 bytes * @param length how much data to encrypt */ public void encrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int length) { encrypt(payload, payloadIndex, out, outIndex, sessionKey, iv, 0, length); } /** * Encrypt the payload with the session key. * This just copies payload to out, see extension for the real thing. * * @param payload data to be encrypted * @param payloadIndex index into the payload to start encrypting * @param out where to store the result * @param outIndex where in out to start writing * @param sessionKey private esession key to encrypt to * @param iv IV for CBC * @param length how much data to encrypt */ public void encrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int ivOffset, int length) { System.arraycopy(payload, payloadIndex, out, outIndex, length); _log.logAlways(Log.WARN, "AES is disabled"); } /** * Encrypt the SHA-256 Hash of the IV, the 4 byte length, and the payload, * with random padding up to the paddedSize, rounded up to the next multiple of 16. * * @param paddedSize minimum size of the output * @param iv IV for CBC, must be 16 bytes * @return null on error * @deprecated unused */ @Deprecated public byte[] safeEncrypt(byte payload[], SessionKey sessionKey, byte iv[], int paddedSize) { if ((iv == null) || (payload == null) || (sessionKey == null) || (iv.length != 16)) return null; int size = Hash.HASH_LENGTH + 4 // sizeof(payload) + payload.length; int padding = ElGamalAESEngine.getPaddingSize(size, paddedSize); byte data[] = new byte[size + padding]; _context.sha().calculateHash(iv, 0, 16, data, 0); int cur = Hash.HASH_LENGTH; DataHelper.toLong(data, cur, 4, payload.length); cur += 4; System.arraycopy(payload, 0, data, cur, payload.length); cur += payload.length; byte paddingData[] = ElGamalAESEngine.getPadding(_context, size, paddedSize); System.arraycopy(paddingData, 0, data, cur, paddingData.length); encrypt(data, 0, data, 0, sessionKey, iv, data.length); return data; } /** * See safeEncrypt() for description. * WARNING - no check for maximum length here, OOM DOS possible, fix it if you're going to use this. * * @param iv IV for CBC, must be 16 bytes * @return null on error * @deprecated unused */ @Deprecated public byte[] safeDecrypt(byte payload[], SessionKey sessionKey, byte iv[]) { if ((iv == null) || (payload == null) || (sessionKey == null) || (iv.length != 16)) return null; byte decr[] = new byte[payload.length]; decrypt(payload, 0, decr, 0, sessionKey, iv, payload.length); byte h[] = SimpleByteCache.acquire(Hash.HASH_LENGTH); _context.sha().calculateHash(iv, 0, 16, h, 0); boolean eq = DataHelper.eq(decr, 0, h, 0, Hash.HASH_LENGTH); SimpleByteCache.release(h); if (!eq) { _log.error("Hash does not match [key=" + sessionKey + " / iv =" + DataHelper.toString(iv, iv.length) + "]", new Exception("Hash error")); return null; } int cur = Hash.HASH_LENGTH; long len = DataHelper.fromLong(decr, cur, 4); cur += 4; if (cur + len > decr.length) { _log.error("Not enough to read"); return null; } byte data[] = new byte[(int)len]; System.arraycopy(decr, cur, data, 0, (int)len); return data; } /** Decrypt the data with the session key * @param payload data to be decrypted * @param payloadIndex index into the payload to start decrypting * @param out where to store the cleartext * @param outIndex where in out to start writing * @param sessionKey private session key to decrypt to * @param iv IV for CBC * @param length how much data to decrypt */ public void decrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int length) { decrypt(payload, payloadIndex, out, outIndex, sessionKey, iv, 0, length); } /** * Decrypt the data with the session key. * This just copies payload to out, see extension for the real thing. * * @param payload data to be decrypted * @param payloadIndex index into the payload to start decrypting * @param out where to store the cleartext * @param outIndex where in out to start writing * @param sessionKey private session key to decrypt to * @param iv IV for CBC * @param length how much data to decrypt */ public void decrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int ivOffset, int length) { System.arraycopy(payload, payloadIndex, out, outIndex, length); _log.logAlways(Log.WARN, "AES is disabled"); } /** * This just copies payload to out, see extension for the real thing. * @param sessionKey unused */ public void encryptBlock(byte payload[], int inIndex, SessionKey sessionKey, byte out[], int outIndex) { System.arraycopy(payload, inIndex, out, outIndex, out.length - outIndex); } /** * This just copies payload to rv, see extension for the real thing. * * @param payload encrypted data * @param sessionKey private session key */ public void decryptBlock(byte payload[], int inIndex, SessionKey sessionKey, byte rv[], int outIndex) { System.arraycopy(payload, inIndex, rv, outIndex, rv.length - outIndex); } /****** public static void main(String args[]) { I2PAppContext ctx = new I2PAppContext(); SessionKey key = ctx.keyGenerator().generateSessionKey(); byte iv[] = new byte[16]; RandomSource.getInstance().nextBytes(iv); byte sbuf[] = new byte[16]; RandomSource.getInstance().nextBytes(sbuf); byte se[] = new byte[16]; ctx.aes().encrypt(sbuf, 0, se, 0, key, iv, sbuf.length); byte sd[] = new byte[16]; ctx.aes().decrypt(se, 0, sd, 0, key, iv, se.length); ctx.logManager().getLog(AESEngine.class).debug("Short test: " + DataHelper.eq(sd, sbuf)); byte lbuf[] = new byte[1024]; RandomSource.getInstance().nextBytes(sbuf); byte le[] = ctx.aes().safeEncrypt(lbuf, key, iv, 2048); byte ld[] = ctx.aes().safeDecrypt(le, key, iv); ctx.logManager().getLog(AESEngine.class).debug("Long test: " + DataHelper.eq(ld, lbuf)); } ******/ }