Java tutorial
package org.tramaci.onionmail; /* * Copyright (C) 2011 by Tramaci.Org * This file is part of OnionMail (http://onionmail.info) * * OnionMail is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This source code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this source code; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.PrintWriter; import java.math.BigInteger; import java.net.InetAddress; import java.net.InetSocketAddress; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.MessageDigest; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Signature; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Calendar; import java.util.Date; import java.util.zip.CRC32; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; public class Stdio { private static final int[] KeyPairStruct = new int[] { 4, 2, 8, 2 }; public static final int PKCSPaddingSize = 11; public static byte[] Stosw(short[] arr) throws Exception { int cx = arr.length; byte[] o = new byte[cx * 2]; for (int ax = 0; ax < cx; ax++) Poke(ax * 2, (int) arr[ax], o); return o; } public static short[] Lodsw(byte[] arr) throws Exception { int cx = arr.length >> 1; short[] o = new short[cx]; for (int ax = 0; ax < cx; ax++) o[ax] = (short) Peek(ax * 2, arr); return o; } public static byte[] RSAEncDataP(byte[] Data, PublicKey K, int bsize) throws Exception { int cx = Data.length; byte[] raw = new byte[cx + 2]; System.arraycopy(Data, 0, raw, 2, cx); Poke(0, cx, raw); return RSAEncData(raw, K, bsize); } public static byte[] RSADecDataP(byte[] Data, PrivateKey K, int bsize) throws Exception { byte[] raw = RSADecData(Data, K, bsize); int cx = Peek(0, raw); if (cx < 0 || cx > raw.length - 2) throw new Exception("Invalid RSA/DATA"); byte[] out = new byte[cx]; System.arraycopy(raw, 2, out, 0, cx); return out; } public static byte[] RSAEncData(byte[] Data, PublicKey K, int bsize) throws Exception { byte[][] Blo = DivBlock(Data, bsize - PKCSPaddingSize, true); int cx = Blo.length; for (int ax = 0; ax < cx; ax++) Blo[ax] = RSAEncP(Blo[ax], K); return MulBlock(Blo, bsize); } public static byte[] RSADecData(byte[] Data, PrivateKey K, int bsize) throws Exception { //Attenzione alla fine ci saranno dei dati in pi byte[][] Blo = DivBlock(Data, bsize, false); int cx = Blo.length; for (int ax = 0; ax < cx; ax++) Blo[ax] = RSADecP(Blo[ax], K); return MulBlock(Blo, bsize - PKCSPaddingSize); } protected static byte[][] AddChunk(byte[][] d, byte[] c) throws Exception { int cx = d.length; byte[][] out = new byte[cx + 1][]; for (int ax = 0; ax < cx; ax++) out[ax] = d[ax]; out[cx] = c; return out; } protected static byte[][] RemChunks(byte[][] d, int re) throws Exception { int dx = d.length - re; byte[][] out = new byte[dx][]; for (int ax = 0; ax < dx; ax++) out[ax] = d[ax]; return out; } public static byte[] MxAccuCrypter(byte[][] in, int magic32, PublicKey K, PrivateKey S) throws Exception { byte[] dt = MxAccuShifter(in, 0x1234, true); byte[] ts = md5(dt); byte[] ke = new byte[16]; byte[] si = new byte[0]; NewRnd(ke); dt = AESEnc(GetAESKey(ke), ts, dt); byte[] He = MXImplode(new byte[][] { ke, ts }, 0x12345678); He = RSAEncP(He, K); if (S != null) si = RSASign(dt, S); return MXImplode(new byte[][] { He, dt, si }, magic32); } protected static byte[][] MxDaccuDECrypter(byte[] in, int magic32, PrivateKey K, PublicKey S) throws Exception { byte[][] fi = MXExplode(in, magic32); byte[] He = RSADecP(fi[0], K); byte[][] Hec = MXExplode(He, 0x12345678); SecretKey Ke = GetAESKey(Hec[0]); if (S != null && fi[2].length == 0) throw new Exception("_MX:SIGN:N"); if (S != null && fi[2].length > 0) { if (!RSAVerify(fi[1], fi[2], S)) throw new Exception("_MX:SIGN"); } byte[] dt = AESDec(Ke, Hec[1], fi[1]); byte[] ts = md5(dt); for (int ax = 0; ax < 16; ax++) if (ts[ax] != Hec[1][ax]) throw new Exception("_MX:KEY"); return MxDaccuShifter(dt, 0x1234); } protected static long MyUserCode(String login) { CRC32 C = new CRC32(); C.update(login.getBytes()); long d = C.getValue(); d ^= d << 1; d &= 0xFFFFFFFFL; return d; } protected static long GetKeyId(PublicKey K) throws Exception { RSAPublicKey L = (RSAPublicKey) K; BigInteger a = L.getPublicExponent(); BigInteger b = L.getModulus(); byte[] t0 = md5a(new byte[][] { a.toByteArray(), b.toByteArray() }); long uid = 0; for (int ax = 0; ax < 8; ax++) { uid <<= 8; uid |= (long) (255 & t0[ax]); } uid &= 0x7FFFFFFFFFFFFFFFL; return uid; } protected static byte[] Public2Arr(PublicKey pub) throws Exception { X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(pub.getEncoded()); return x509EncodedKeySpec.getEncoded(); } protected static KeyPair RSAKeyGen(int bits) throws Exception { KeyPairGenerator keyGen; if (Main.RSAGenBC) keyGen = KeyPairGenerator.getInstance("RSA", "BC"); else keyGen = KeyPairGenerator.getInstance("RSA"); if (Main.RandomHeart != null) keyGen.initialize(bits, Stdio.getRandom()); else keyGen.initialize(bits); KeyPair me = keyGen.genKeyPair(); return me; } private static byte[] Seeder = null; protected static SecureRandom getRandom() throws Exception { SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); long x = System.currentTimeMillis(); if (Seeder == null) { long t = System.currentTimeMillis() + 500 + random.nextInt(500); if (new File(Main.RandomHeart).exists()) Seeder = Stdio.file_get_bytes(Main.RandomHeart); if (Seeder == null || Seeder.length < 1023) { Seeder = new byte[1024]; random.nextBytes(Seeder); } while (x < t) { byte[] b = Stdio.sha512a(new byte[][] { Seeder, Long.toString(x, 36).getBytes() }); x = System.currentTimeMillis(); random.setSeed(b); random.setSeed(Seeder); random.nextBytes(Seeder); } Stdio.file_put_bytes(Main.RandomHeart, Seeder); } byte[] b = Stdio.sha512a(new byte[][] { Seeder, Long.toString(x, 36).getBytes() }); random.setSeed(b); random.setSeed(Seeder); random.nextBytes(Seeder); return random; } protected static long NewRndLong() { try { SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); return random.nextLong(); } catch (Exception E) { return ((long) (Math.random() * Math.pow(2, 62)) ^ System.currentTimeMillis()); } } protected static int NewRndInt(int mx) { try { SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); return random.nextInt(mx); } catch (Exception E) { return (int) ((int) (Math.random() * Math.pow(2, 31)) ^ System.currentTimeMillis() & 0x7FFFFFFFL); } } protected static void NewRnd(byte[] rnd) { try { SecureRandom random; if (Main.RandomHeart != null) { random = Stdio.getRandom(); long x = System.currentTimeMillis(); byte[] b = Stdio.sha512a(new byte[][] { Seeder, Long.toString(x, 36).getBytes() }); random.setSeed(b); random.setSeed(Seeder); int cx = rnd.length; b = new byte[cx]; random.nextBytes(b); random.nextBytes(rnd); for (int ax = 0; ax < cx; ax++) rnd[ax] ^= b[ax]; } else { random = SecureRandom.getInstance("SHA1PRNG"); random.nextBytes(rnd); } } catch (Exception E) { } } public static byte[] MxAccuShifter(byte[][] dta, int magic) throws Exception { return MxAccuShifter(dta, magic, false); } public static void Poke(int addr, int valu, byte[] ram) { ram[addr] = (byte) (255 & valu); ram[addr + 1] = (byte) (255 & (valu >> 8)); } public static int Peek(int addr, byte[] ram) { int valu = (int) (255 & ram[addr]); valu |= (int) ((255 & ram[addr + 1]) << 8); return valu; } public static void PokeB(int addr, int valu, byte[] ram) { ram[addr + 1] = (byte) (255 & valu); ram[addr] = (byte) (255 & (valu >> 8)); } public static void PokeX(int addr, long valu, int bytes, byte[] ram) { for (int ax = 0; ax < bytes; ax++) { ram[addr + ax] = (byte) (255 & valu); valu >>= 8; } } public static long PeekX(int addr, int bytes, byte[] ram) { long valu = 0; for (int ax = bytes - 1; ax > -1; ax--) { valu <<= 8; valu |= (long) (255 & ram[addr + ax]); } return valu; } public static int PeekB(int addr, byte[] ram) { int valu = (int) (255 & ram[addr + 1]); valu |= (int) ((255 & ram[addr]) << 8); return valu; } public static int sumlen(byte[][] raw) throws Exception { int le = 0; for (int ax = 0; ax < raw.length; ax++) le += raw[ax].length; return le; } public static byte[] trimarr(byte[] ar, int sz) throws Exception { byte[] o = new byte[sz]; for (int ax = 0; ax < sz; ax++) o[ax] = ar[ax]; return o; } public static byte[] Naccu(int max, int sz) { int cx = sz >> 4; if ((sz & 3) != 0) cx++; cx *= 16; if (cx == 0) cx = 16; byte[] raw = new byte[cx]; Poke(0, 0, raw); int bp = 6 + (max * 4); Poke(2, bp, raw); Poke(4, 0, raw); return raw; } public static byte[] Stosxm(long[] dta, int[] sz) { int mx = 0; for (int ax = 0; ax < sz.length; ax++) mx += sz[ax]; int bp = 0; byte[] re = new byte[mx]; for (int w = 0; w < dta.length; w++) { long dd = dta[w]; for (int al = 0; al < sz[w]; al++) { re[bp++] = (byte) (dd & 255); dd >>= 8; } } return re; } public static int Stosxmp(byte[] re, long[] dta, int[] sz, int bp) { for (int w = 0; w < dta.length; w++) { long dd = dta[w]; for (int al = 0; al < sz[w]; al++) { re[bp++] = (byte) (dd & 255); dd >>= 8; } } return bp; } public static byte[] Stosxmb(long[] dta, int[] sz) { int mx = 0; for (int ax = 0; ax < sz.length; ax++) mx += sz[ax]; int bp = 0; byte[] re = new byte[mx]; for (int w = 0; w < dta.length; w++) { long dd = dta[w]; for (int al = 0; al < sz[w]; al++) { re[bp++] = (byte) (dd & 255); dd >>= 8; } } return re; } public static long[][] Lodsxma(byte[] dta, int[] sz) { int cx = sz.length; int bx = 0; for (int ax = 0; ax < cx; ax++) bx += sz[ax]; cx = (int) Math.floor(dta.length / bx); long[][] rs = new long[cx][]; int ptr = 0; for (int ax = 0; ax < cx; ax++) { rs[ax] = Stdio.Lodsxmp(dta, sz, ptr); ptr += bx; } return rs; } public static long[] Lodsxmp(byte[] dta, int[] sz, int ptr) { int mx = sz.length; long[] re = new long[mx]; int bp = 0; long dd = 0; int ebp = 0; for (int ax = 0; ax < mx; ax++) { bp = sz[ax] - 1; dd = 0; for (int al = 0; al < sz[ax]; al++) { dd <<= 8; dd ^= (long) (dta[ebp + (bp--) + ptr] & 255); } ebp += sz[ax]; re[ax] = dd; } return re; } public static byte[] Stosxma(long[][] in, int sz[]) { int bx = 0; int cx = sz.length; for (int ax = 0; ax < cx; ax++) bx += sz[ax]; cx = in.length; byte[] rs = new byte[bx * cx]; int bp = 0; for (int ax = 0; ax < cx; ax++) bp = Stdio.Stosxmp(rs, in[ax], sz, bp); return rs; } public static long[] Lodsxm(byte[] dta, int[] sz) { int mx = sz.length; long[] re = new long[mx]; int bp = 0; long dd = 0; int ebp = 0; for (int ax = 0; ax < mx; ax++) { bp = sz[ax] - 1; dd = 0; for (int al = 0; al < sz[ax]; al++) { dd <<= 8; dd ^= (long) (dta[ebp + (bp--)] & 255); } ebp += sz[ax]; re[ax] = dd; } return re; } public static byte[] StosxNP(long[] dta, int sz) { int mx = dta.length * sz; int bp = 0; byte[] re = new byte[mx]; for (int w = 0; w < dta.length; w++) { long dd = dta[w]; for (int al = 0; al < sz; al++) { re[bp++] = (byte) (dd & 255); dd >>= 8; } } return re; } public static byte[] Stosx(long[] dta, int sz) { int mx = dta.length * sz; int bp = 0; byte[] re = new byte[mx]; for (int w = 0; w < dta.length; w++) { long dd = dta[w]; for (int al = 0; al < sz; al++) { re[bp++] = (byte) (dd & 255); dd >>= 8; } } return re; } public static long[] Lodsx(byte[] dta, int sz) { int mx = (int) Math.floor(dta.length / sz); if ((dta.length % sz) != 0) mx++; long[] re = new long[mx]; int bp = 0; long dd = 0; int ebp = 0; for (int ax = 0; ax < mx; ax++) { bp = sz - 1; dd = 0; for (int al = 0; al < sz; al++) { dd <<= 8; dd ^= (long) (dta[ebp + (bp--)] & 255); } ebp += sz; re[ax] = dd; } return re; } public static int[] Lodsxi(byte[] dta, int sz) { int mx = (int) Math.floor(dta.length / sz); if ((dta.length % sz) != 0) mx++; int[] re = new int[mx]; int bp = 0; int dd = 0; int ebp = 0; for (int ax = 0; ax < mx; ax++) { bp = sz - 1; dd = 0; for (int al = 0; al < sz; al++) { dd <<= 8; dd ^= (int) (dta[ebp + (bp--)] & 255); } ebp += sz; re[ax] = dd; } return re; } public static byte[] Stosxi(int[] dta, int sz) { int mx = dta.length * sz; int bp = 0; byte[] re = new byte[mx]; for (int w = 0; w < dta.length; w++) { int dd = dta[w]; for (int al = 0; al < sz; al++) { re[bp++] = (byte) (dd & 255); dd >>= 8; } } return re; } public static long[] Lodsxc(byte[] dta, int sz, int mx) { long[] re = new long[mx]; int bp = 0; long dd = 0; int ebp = 0; for (int ax = 0; ax < mx; ax++) { bp = sz - 1; dd = 0; for (int al = 0; al < sz; al++) { dd <<= 8; dd ^= (long) (dta[ebp + (bp--)] & 255); } ebp += sz; re[ax] = dd; } return re; } public static SecretKey GetAESKey(byte[] in) throws Exception { SecretKey key = new SecretKeySpec(in, "AES"); return key; } public static byte[] AESEnc(SecretKey Tk, byte[] IV, byte[] data) throws Exception { IvParameterSpec iv = new IvParameterSpec(IV); Cipher ecipher = Cipher.getInstance("AES/CBC/NoPadding"); ecipher.init(Cipher.ENCRYPT_MODE, Tk, iv); byte[] enc = ecipher.doFinal(data); return enc; } public static byte[] AESDec(SecretKey Tk, byte[] IV, byte[] data) throws Exception { IvParameterSpec iv = new IvParameterSpec(IV); Cipher ecipher = Cipher.getInstance("AES/CBC/NoPadding"); ecipher.init(Cipher.DECRYPT_MODE, Tk, iv); byte[] enc = ecipher.doFinal(data); return enc; } public static SecretKey GetBlowfishKey(byte[] in) throws Exception { SecretKey key = new SecretKeySpec(in, "Blowfish"); return key; } public static byte[] BlowfishEnc(SecretKey Tk, byte[] IV, byte[] data) throws Exception { IvParameterSpec iv = new IvParameterSpec(IV); Cipher ecipher = Cipher.getInstance("Blowfish/CBC/NoPadding"); ecipher.init(Cipher.ENCRYPT_MODE, Tk, iv); byte[] enc = ecipher.doFinal(data); return enc; } public static byte[] BlowfishDec(SecretKey Tk, byte[] IV, byte[] data) throws Exception { IvParameterSpec iv = new IvParameterSpec(IV); Cipher ecipher = Cipher.getInstance("Blowfish/CBC/NoPadding"); ecipher.init(Cipher.DECRYPT_MODE, Tk, iv); byte[] enc = ecipher.doFinal(data); return enc; } private static byte[] AES2cipher(PaddedBufferedBlockCipher cipher, byte[] data) throws Exception { int cx = cipher.getOutputSize(data.length); byte[] out = new byte[cx]; int le1 = cipher.processBytes(data, 0, data.length, out, 0); int le2 = cipher.doFinal(out, le1); int le3 = le1 + le2; byte[] result = new byte[le3]; System.arraycopy(out, 0, result, 0, result.length); return result; } public static byte[] AESEncMul(byte[] keySpec, byte[] data) throws Exception { int cx = keySpec.length; int round = (int) Math.floor(cx / 48); if (round == 0) throw new Exception("AESEncMul: Invalid KeySpec"); byte[][] Key = new byte[round][32]; byte[][] IV = new byte[round][16]; for (int ax = 0; ax < round; ax++) { int bp = 48 * ax; System.arraycopy(keySpec, bp, Key[ax], 0, 32); System.arraycopy(keySpec, bp + 16, IV[ax], 0, 16); } return AESEnc2m(Key, IV, data); } public static byte[] AESEncMulP(byte[] keySpec, byte[] data) throws Exception { int cx = keySpec.length; int round = (int) Math.floor(cx / 48); if (round == 0) throw new Exception("AESEncMul: Invalid KeySpec"); byte[][] Key = new byte[round][32]; byte[][] IV = new byte[round][16]; byte[] keyp = Stdio.sha256(keySpec); byte[] ivp = Stdio.md5a(new byte[][] { keyp, keySpec }); data = Stdio.AES2Enc(keyp, ivp, data); for (int ax = 0; ax < round; ax++) { int bp = 48 * ax; System.arraycopy(keySpec, bp, Key[ax], 0, 32); System.arraycopy(keySpec, bp + 16, IV[ax], 0, 16); } return AESEnc2m(Key, IV, data); } public static byte[] AESDecMulP(byte[] keySpec, byte[] data) throws Exception { int cx = keySpec.length; int round = (int) Math.floor(cx / 48); if (round == 0) throw new Exception("AESEncMul: Invalid KeySpec"); byte[][] Key = new byte[round][32]; byte[][] IV = new byte[round][16]; byte[] keyp = Stdio.sha256(keySpec); byte[] ivp = Stdio.md5a(new byte[][] { keyp, keySpec }); for (int ax = 0; ax < round; ax++) { int bp = 48 * ax; System.arraycopy(keySpec, bp, Key[ax], 0, 32); System.arraycopy(keySpec, bp + 16, IV[ax], 0, 16); } data = AESDec2m(Key, IV, data); data = Stdio.AES2Dec(keyp, ivp, data); return data; } public static byte[] AESDecMul(byte[] keySpec, byte[] data) throws Exception { int cx = keySpec.length; int round = (int) Math.floor(cx / 48); if (round == 0) throw new Exception("AESEncMul: Invalid KeySpec"); byte[][] Key = new byte[round][32]; byte[][] IV = new byte[round][16]; for (int ax = 0; ax < round; ax++) { int bp = 48 * ax; System.arraycopy(keySpec, bp, Key[ax], 0, 32); System.arraycopy(keySpec, bp + 16, IV[ax], 0, 16); } return AESDec2m(Key, IV, data); } public static byte[] AESEnc2m(byte[][] key, byte[][] iv, byte[] data) throws Exception { byte[][] blo = Stdio.DivBlock(data, 16, false); int cx = blo.length; int kc = key.length; for (int kx = 0; kx < kc; kx++) { CBCBlockCipher aes = new CBCBlockCipher(new AESEngine()); CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key[kx]), iv[kx]); aes.init(true, ivAndKey); for (int ax = 0; ax < cx; ax++) aes.processBlock(blo[ax], 0, blo[ax], 0); } data = Stdio.MulBlock(blo, 16); blo = null; return data; } public static byte[] AESDec2m(byte[][] key, byte[][] iv, byte[] data) throws Exception { byte[][] blo = Stdio.DivBlock(data, 16, false); int cx = blo.length; int kc = key.length - 1; for (int kx = kc; kx > -1; kx--) { CBCBlockCipher aes = new CBCBlockCipher(new AESEngine()); CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key[kx]), iv[kx]); aes.init(false, ivAndKey); for (int ax = 0; ax < cx; ax++) aes.processBlock(blo[ax], 0, blo[ax], 0); } data = Stdio.MulBlock(blo, 16); blo = null; return data; } public static byte[] AESEnc2(byte[] key, byte[] iv, byte[] data) throws Exception { byte[][] blo = Stdio.DivBlock(data, 16, false); CBCBlockCipher aes = new CBCBlockCipher(new AESEngine()); CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv); aes.init(true, ivAndKey); int cx = blo.length; for (int ax = 0; ax < cx; ax++) aes.processBlock(blo[ax], 0, blo[ax], 0); data = Stdio.MulBlock(blo, 16); blo = null; return data; } public static byte[] AESDec2(byte[] key, byte[] iv, byte[] data) throws Exception { byte[][] blo = Stdio.DivBlock(data, 16, false); CBCBlockCipher aes = new CBCBlockCipher(new AESEngine()); CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv); aes.init(false, ivAndKey); int cx = blo.length; for (int ax = 0; ax < cx; ax++) aes.processBlock(blo[ax], 0, blo[ax], 0); data = Stdio.MulBlock(blo, 16); blo = null; return data; } public static byte[] AES2Enc(byte[] key, byte[] iv, byte[] data) throws Exception { PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine())); CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv); aes.init(true, ivAndKey); return AES2cipher(aes, data); } public static byte[] AES2Dec(byte[] key, byte[] iv, byte[] data) throws Exception { try { PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine())); CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv); aes.init(false, ivAndKey); return AES2cipher(aes, data); } catch (Exception E) { throw new Exception("!Invalid KEY for data" + E.getMessage()); } } public static boolean RSAVerify(byte[] dta, byte[] sign, PublicKey K) throws Exception { Signature rsaVerifier = Signature.getInstance("SHA1WithRSA"); rsaVerifier.initVerify(K); rsaVerifier.update(dta); return rsaVerifier.verify(sign); } public static byte[] Private2Arr(PrivateKey privateKey) throws Exception { PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded()); return pkcs8EncodedKeySpec.getEncoded(); } public static PrivateKey Arr2Private(byte[] sk) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(sk); return keyFactory.generatePrivate(privateKeySpec); } public static PublicKey Arr2Public(byte[] data, String algorithm) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance(algorithm); X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(data); PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); return publicKey; } public static PublicKey Arr2Public(byte[] data) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(data); PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); return publicKey; } public static void SaveSKPR(String path, KeyPair keyPair, byte[] pax, boolean priv) throws Exception { FileOutputStream F = new FileOutputStream(path); byte[] sal = new byte[32]; NewRnd(sal); F.write(sal); SecretKey KK = GetAESKey(md5a(new byte[][] { md5(pax), sal })); byte[] IV = md5a(new byte[][] { md5(sal), md5(pax), sal }); PublicKey publicKey = keyPair.getPublic(); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded()); byte[] kt = x509EncodedKeySpec.getEncoded(); byte[] kb = _ArrPad(kt, 16, true); byte[] m = md5(kb); F.write(m); long[] h = new long[4]; h[0] = 0x12345678; h[1] = kb.length; h[2] = GetKeyId(publicKey); h[3] = (int) (65534 & Calendar.getInstance().getTimeInMillis()); h[3] ^= (int) (Math.random() * 65535); h[3] &= 65534; if (priv) h[3] |= 1; byte[] t1 = Stosxm(h, KeyPairStruct); kt = AESEnc(KK, IV, t1); F.write(kt); kt = AESEnc(KK, IV, kb); F.write(kt); if (!priv) { F.close(); return; } PrivateKey privateKey = keyPair.getPrivate(); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded()); kt = pkcs8EncodedKeySpec.getEncoded(); kb = _ArrPad(kt, 16, true); m = md5(kb); F.write(m); h = new long[4]; h[0] = 0x12345678; h[1] = kb.length; h[2] = GetKeyId(publicKey); h[3] = priv ? 0x8ec1 : 0x8cc0; t1 = Stosxm(h, KeyPairStruct); kt = AESEnc(KK, IV, t1); F.write(kt); kt = AESEnc(KK, IV, kb); F.write(kt); F.close(); } public static KeyPair LoadSKPR(String path, byte[] pax, int skp) throws Exception { FileInputStream F = new FileInputStream(path); if (skp != 0) F.skip(skp); byte[] sal = new byte[32]; F.read(sal); SecretKey KK = GetAESKey(md5a(new byte[][] { md5(pax), sal })); byte[] IV = md5a(new byte[][] { md5(sal), md5(pax), sal }); byte[] m = new byte[16]; F.read(m); byte[] hb = new byte[16]; F.read(hb); hb = AESDec(KK, IV, hb); long[] h = Lodsxm(hb, KeyPairStruct); if (h[0] != 0x12345678) { F.close(); throw new Exception("KEY:1.1.1"); } boolean priv = false; if ((h[3] & 1) != 0) priv = true; int cx = (int) h[1]; byte[] kb = new byte[cx]; F.read(kb); byte[] k1 = AESDec(KK, IV, kb); byte[] v = md5(k1); for (int ax = 0; ax < 16; ax++) if (v[ax] != m[ax]) { F.close(); throw new Exception("KEY:1.1.2"); } byte[] pk = _ArrUPadr(k1); byte[] sk = null; KeyFactory keyFactory = KeyFactory.getInstance("RSA"); X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pk); PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); if (priv) { m = new byte[16]; F.read(m); hb = new byte[16]; F.read(hb); hb = AESDec(KK, IV, hb); h = Lodsxm(hb, KeyPairStruct); if (h[0] != 0x12345678) { F.close(); throw new Exception("KEY:1.2.1"); } cx = (int) h[1]; kb = new byte[cx]; F.read(kb); byte[] k2 = AESDec(KK, IV, kb); v = md5(k2); for (int ax = 0; ax < 16; ax++) if (v[ax] != m[ax]) { F.close(); throw new Exception("KEY:1.2.2"); } sk = _ArrUPadr(k2); PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(sk); PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec); F.close(); return new KeyPair(publicKey, privateKey); } F.close(); return new KeyPair(publicKey, null); } public static byte[] _ArrUPadr(byte[] I) throws Exception { int pad = (int) (255 & I[0]); pad ^= (int) ((255 & I[1]) << 8); int cx = pad; byte[] re = new byte[cx]; for (int ax = 0; ax < cx; ax++) { re[ax] = I[ax + 2]; } return re; } public static byte[] _ArrPad(byte[] I, int bsize, boolean rnd) { int bp = I.length + 2; int mx = (int) Math.floor(bp / bsize); if ((bp % bsize) != 0) mx++; byte[] re = new byte[mx * bsize]; if (rnd) NewRnd(re); bp = I.length; re[0] = (byte) (bp & 255); re[1] = (byte) ((bp >> 8) & 255); bp = 2; for (int ax = 0; ax < I.length; ax++) re[bp++] = I[ax]; return re; } public static void file_put_bytes(String name, byte[] data) throws Exception { FileOutputStream fo = new FileOutputStream(name); fo.write(data); fo.close(); } public static byte[] file_get_bytes(String name) throws Exception { File file = new File(name); long length = file.length(); if (length > 512384) throw new Exception("File Too big"); byte[] data = new byte[(int) length]; FileInputStream f = new FileInputStream(name); f.read(data); f.close(); return data; } public static byte[] HexData(String he) { byte[] out; int cx = he.length(); int bx = 0; int dx = 0; out = new byte[(int) (cx / 2)]; for (int ax = 0; ax < cx; ax += 2) { bx = (int) Long.parseLong(he.substring(ax, ax + 2), 16); out[dx++] = (byte) (bx & 255); } return out; } public static byte[] RSASign(byte[] dta, PrivateKey K) throws Exception { Signature rsaSigner = Signature.getInstance("SHA1WithRSA"); rsaSigner.initSign(K); rsaSigner.update(dta); byte[] sign = rsaSigner.sign(); return sign; } public static String Dump(byte[] data) { String o = new String(); int cx = data.length; int bx; for (int ax = 0; ax < cx; ax++) { bx = data[ax] & 255; if (bx < 16) o = o + "0"; o = o + Integer.toHexString(bx); } return o; } public static byte[] md5a(byte[][] in) { MessageDigest digest; try { digest = java.security.MessageDigest.getInstance("MD5"); for (int ax = 0; ax < in.length; ax++) digest.update(in[ax]); return digest.digest(); } catch (Exception E) { return new byte[16]; } } public static byte[] md5(byte[] in) { MessageDigest digest; try { digest = java.security.MessageDigest.getInstance("MD5"); digest.update(in); return digest.digest(); } catch (Exception E) { return new byte[16]; } } public static byte[] sha1(byte[] data) throws Exception { MessageDigest md = MessageDigest.getInstance("SHA-1"); return md.digest(data); } public static byte[] sha1a(byte[][] data) throws Exception { MessageDigest md = MessageDigest.getInstance("SHA-1"); int cx = data.length; for (int ax = 0; ax < cx; ax++) md.update(data[ax]); return md.digest(); } public static byte[] sha512(byte[] a) throws Exception { Digest d = new SHA512Digest(); byte[] r = new byte[d.getDigestSize()]; d.update(a, 0, a.length); d.doFinal(r, 0); return r; } public static byte[] sha512a(byte[][] a) throws Exception { Digest d = new SHA512Digest(); byte[] r = new byte[d.getDigestSize()]; int cx = a.length; for (int ax = 0; ax < cx; ax++) d.update(a[ax], 0, a[ax].length); d.doFinal(r, 0); return r; } public static byte[] sha256(byte[] a) throws Exception { Digest d = new SHA256Digest(); byte[] r = new byte[d.getDigestSize()]; d.update(a, 0, a.length); d.doFinal(r, 0); return r; } public static byte[] sha256a(byte[][] a) throws Exception { Digest d = new SHA256Digest(); byte[] r = new byte[d.getDigestSize()]; int cx = a.length; for (int ax = 0; ax < cx; ax++) d.update(a[ax], 0, a[ax].length); d.doFinal(r, 0); return r; } public static byte[] RSAEnc(byte[] I, PublicKey you) throws Exception { Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, you); byte[] cipherData = cipher.doFinal(I); return cipherData; } public static byte[] RSADec(byte[] I, PrivateKey my) throws Exception { Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding"); cipher.init(Cipher.DECRYPT_MODE, my); byte[] cipherData = cipher.doFinal(I); return cipherData; } public static byte[] RSAEncP(byte[] I, PublicKey you) throws Exception { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, you); byte[] cipherData = cipher.doFinal(I); return cipherData; } public static byte[] RSADecP(byte[] I, PrivateKey my) throws Exception { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, my); byte[] cipherData = cipher.doFinal(I); return cipherData; } public static byte[][] DivBlock(byte[] dta, int size, boolean padrand) throws Exception { int blo = dta.length / size; if ((dta.length % size) != 0) blo++; byte[][] blk = new byte[blo][size]; if (padrand) NewRnd(blk[blo - 1]); int cx = blo - 1; for (int ax = 0; ax < cx; ax++) System.arraycopy(dta, size * ax, blk[ax], 0, size); System.arraycopy(dta, cx * size, blk[blo - 1], 0, dta.length - (cx * size)); return blk; } public static byte[] MulBlock(byte[][] blk, int size) throws Exception { int cx = blk.length; byte[] out = new byte[cx * size]; for (int ax = 0; ax < cx; ax++) System.arraycopy(blk[ax], 0, out, ax * size, size); return out; } public static byte[] MulBlockT(byte[][] blk, int size, int trim) throws Exception { int cx = blk.length; byte[] out = new byte[cx * trim]; for (int ax = 0; ax < cx; ax++) System.arraycopy(blk[ax], 0, out, ax * size, trim); return out; } public static byte[] MxAccuShifter16(byte[][] arr, int magic, boolean rnd) throws Exception { int top = 0; int obj = arr.length; if (obj > 65535) throw new Exception("_MX:TOOBIG"); for (int ax = 0; ax < obj; ax++) top += arr[ax].length; int bp = 7 + (obj * 2); top += bp; int oldtop = top; top = ((top >> 4) + (((top & 15) != 0) ? 1 : 0)) << 4; byte[] out = new byte[top]; if (rnd) { long t0 = System.currentTimeMillis(); for (int ax = oldtop; ax < top; ax++) out[ax] = (byte) (255 & (((long) (Math.random() * 256.0)) ^ (t0 >> (ax & 31)))); } PokeB(0, magic, out); PokeB(2, top, out); out[4] = -1; PokeB(5, obj, out); for (int ax = 0; ax < obj; ax++) { int dx = arr[ax].length; PokeB(7 + (ax * 2), dx, out); System.arraycopy(arr[ax], 0, out, bp, dx); bp += dx; } return out; } public static byte[][] MxDaccuShifter16(byte[] in, int magic) throws Exception { int t0 = PeekB(0, in); if (t0 != magic) throw new Exception("_MX:MAGIC " + Integer.toHexString(t0)); int top = PeekB(2, in); if (top > in.length) throw new Exception("_MX:DIM " + top + " " + in.length); int obj = (int) (255 & in[4]); if (obj != 255) throw new Exception("nonMX16"); obj = PeekB(5, in); byte[][] out = new byte[obj][]; int bp = 7 + (obj * 2); for (int ax = 0; ax < obj; ax++) { int dx = PeekB(7 + (ax * 2), in); if (dx + bp > top) throw new Exception("_MX:OVER"); out[ax] = new byte[dx]; System.arraycopy(in, bp, out[ax], 0, dx); bp += dx; } return out; } public static byte[] MxAccuShifter(byte[][] arr, int magic, boolean rnd) throws Exception { int top = 0; int obj = arr.length; if (obj > 254) return MxAccuShifter16(arr, magic, rnd); for (int ax = 0; ax < obj; ax++) top += arr[ax].length; int bp = 5 + (obj * 2); top += bp; int oldtop = top; top = ((top >> 4) + (((top & 15) != 0) ? 1 : 0)) << 4; byte[] out = new byte[top]; if (rnd) { long t0 = System.currentTimeMillis(); for (int ax = oldtop; ax < top; ax++) out[ax] = (byte) (255 & (((long) (Math.random() * 256.0)) ^ (t0 >> (ax & 31)))); } PokeB(0, magic, out); PokeB(2, top, out); out[4] = (byte) (255 & obj); for (int ax = 0; ax < obj; ax++) { int dx = arr[ax].length; PokeB(5 + (ax * 2), dx, out); System.arraycopy(arr[ax], 0, out, bp, dx); bp += dx; } return out; } public static byte[][] MxDaccuShifter(byte[] in, int magic) throws Exception { int t0 = PeekB(0, in); if (t0 != magic) throw new Exception("_MX:MAGIC " + Integer.toHexString(t0)); int obj = (int) (255 & in[4]); if (obj == 255) return MxDaccuShifter16(in, magic); int top = PeekB(2, in); if (top > in.length) throw new Exception("_MX:DIM " + top + " " + in.length); byte[][] out = new byte[obj][]; int bp = 5 + (obj * 2); for (int ax = 0; ax < obj; ax++) { int dx = PeekB(5 + (ax * 2), in); if (dx + bp > top) throw new Exception("_MX:OVER"); out[ax] = new byte[dx]; System.arraycopy(in, bp, out[ax], 0, dx); bp += dx; } return out; } public static byte[] MXImplode(byte[][] arr, int magic32) throws Exception { int top = 0; int obj = arr.length; if (obj > 255) throw new Exception("_MX:TOOBIG"); for (int ax = 0; ax < obj; ax++) top += arr[ax].length; int bp = 7 + (obj * 2); top += bp; byte[] out = new byte[top]; PokeB(2, magic32 & 65535, out); PokeB(0, magic32 >> 16, out); PokeB(4, top, out); out[6] = (byte) (255 & obj); for (int ax = 0; ax < obj; ax++) { int dx = arr[ax].length; PokeB(7 + (ax * 2), dx, out); System.arraycopy(arr[ax], 0, out, bp, dx); bp += dx; } return out; } public static byte[][] MXExplode(byte[] in, int magic32) throws Exception { int t0 = PeekB(2, in); t0 |= PeekB(0, in) << 16; if (t0 != magic32) throw new Exception("_MX:MAGIC"); int top = PeekB(4, in); int obj = (int) (255 & in[6]); byte[][] out = new byte[obj][]; int bp = 7 + (obj * 2); for (int ax = 0; ax < obj; ax++) { int dx = PeekB(7 + (ax * 2), in); if (dx + bp > top) throw new Exception("_MX:OVER"); out[ax] = new byte[dx]; System.arraycopy(in, bp, out[ax], 0, dx); bp += dx; } return out; } public static byte[] EncMulti(byte[] key, byte[] data) throws Exception { byte[][] ke = Stdio.DivBlock(key, 32, false); byte[][] iv = Stdio.DivBlock(key, 16, false); return Stdio.AESEnc2m(ke, iv, data); } public static byte[] DecMulti(byte[] key, byte[] data) throws Exception { byte[][] ke = Stdio.DivBlock(key, 32, false); byte[][] iv = Stdio.DivBlock(key, 16, false); return Stdio.AESDec2m(ke, iv, data); } public static InetSocketAddress Long2Sok(long ip) throws Exception { byte[] i = new byte[4]; i[0] = (byte) (255 & ip); i[1] = (byte) (255 & (ip >> 8)); i[2] = (byte) (255 & (ip >> 16)); i[3] = (byte) (255 & (ip >> 24)); int port = (int) (65535 & (ip >> 32)); return new InetSocketAddress(InetAddress.getByAddress(i), port); } public static long Sok2Long(InetSocketAddress A) throws Exception { long port = A.getPort(); port &= 65535; port = port << 32; InetAddress I = A.getAddress(); byte[] b = I.getAddress(); long r = 0; r = (long) (255 & b[0]); r |= (long) ((255 & b[1]) << 8); r |= (long) ((255 & b[2]) << 16); r |= (long) ((255 & b[3]) << 24); r |= port; return r; } @SuppressWarnings("deprecation") public static synchronized void LogFile(String l, String LogFilen, Config C) throws Exception { Date D = new Date(System.currentTimeMillis() + C.TimeSpoof); String h = (D.getYear() + 1900) + "-" + J.Int2Str(D.getMonth() + 1, 2) + "-" + J.Int2Str(D.getDate(), 2) + " " + J.Int2Str(D.getHours(), 2) + ":" + J.Int2Str(D.getMinutes(), 2) + ":" + J.Int2Str(D.getSeconds(), 2) + "." + J.Int2Str((int) (System.currentTimeMillis() % 1000), 4); l = h + "\t" + l.trim(); PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(LogFilen, true))); try { out.println(l); try { out.close(); } catch (Exception ignore) { } } catch (Exception E) { try { out.close(); } catch (Exception ignore) { } throw E; } } public static void echo(String st) { System.out.print(st); } public static String relativeDate(int tcr) { int t = (int) (System.currentTimeMillis() / 1000L) - tcr; String sign = t < 0 ? "" : "ago"; t = Math.abs(t); if (t < 1000) return "now"; t = (int) Math.floor(t / 60); if (t > 525600) return (Integer.toString((int) Math.floor(t / 525600)) + " Years " + sign).trim(); if (t > 43200) return (Integer.toString((int) Math.floor(t / 43200)) + " Months " + sign).trim(); if (t > 1440) return (Integer.toString((int) Math.floor(t / 1440)) + " Days " + sign).trim(); return (Integer.toString((int) Math.floor(t / 60)) + ":" + Integer.toString((int) (t % 60)) + " " + sign) .trim(); } public static void SFileSave(SrvIdentity srv, byte[][] data, int absId) throws Exception { boolean ServerArea = (absId & 0x10000000) != 0; String FileIntName = "@" + Integer.toString(absId) + "/" + srv.Onion; int Magic = FileIntName.hashCode() ^ (absId & 0x7FFF); SFileSave(srv, FileIntName, data, Magic, ServerArea); } public static byte[][] SFileLoad(SrvIdentity srv, int absId) throws Exception { boolean ServerArea = (absId & 0x10000000) != 0; String FileIntName = "@" + Integer.toString(absId) + "/" + srv.Onion; int Magic = FileIntName.hashCode() ^ (absId & 0x7FFF); return SFileLoad(srv, FileIntName, Magic, ServerArea); } public static void SFileSave(SrvIdentity srv, String FileIntName, byte[][] data, int Magic, boolean ServerArea) throws Exception { byte[] key = Stdio.sha256a(new byte[][] { srv.Sale, FileIntName.getBytes(), srv.Subs[13], Integer.toString(Magic, ServerArea ? 36 : 35).getBytes() }); byte[] iv = Stdio.md5a(new byte[][] { key, Integer.toString(Magic, ServerArea ? 33 : 32).getBytes(), srv.Subs[15 & key[0]], FileIntName.getBytes(), srv.Subs[15 & key[15 & key[1]]] }); FileIntName = new String(srv.Subs[ServerArea ? 15 : 14]) + FileIntName; int a = FileIntName.hashCode(); FileIntName = null; a = a ^ srv.Subs[15][15 & srv.Subs[15][ServerArea ? 7 : 8]]; long b = (a ^ a << 1) & 0x7FFFFFFFFL; String fn = srv.Maildir + (ServerArea ? "/head/" : "/usr/") + Long.toString(b, 16) + ".dat"; byte[] d = Stdio.MxAccuShifter(data, Magic, true); d = Stdio.AESEnc2(key, iv, d); Stdio.file_put_bytes(fn, d); J.WipeRam(key); J.WipeRam(iv); key = null; iv = null; } public static byte[][] SFileLoad(SrvIdentity srv, String FileIntName, int Magic, boolean ServerArea) throws Exception { byte[] key = Stdio.sha256a(new byte[][] { srv.Sale, FileIntName.getBytes(), srv.Subs[13], Integer.toString(Magic, ServerArea ? 36 : 35).getBytes() }); byte[] iv = Stdio.md5a(new byte[][] { key, Integer.toString(Magic, ServerArea ? 33 : 32).getBytes(), srv.Subs[15 & key[0]], FileIntName.getBytes(), srv.Subs[15 & key[15 & key[1]]] }); FileIntName = new String(srv.Subs[ServerArea ? 15 : 14]) + FileIntName; int a = FileIntName.hashCode(); FileIntName = null; a = a ^ srv.Subs[15][15 & srv.Subs[15][ServerArea ? 7 : 8]]; long b = (a ^ a << 1) & 0x7FFFFFFFFL; String fn = srv.Maildir + (ServerArea ? "/head/" : "/usr/") + Long.toString(b, 16) + ".dat"; byte[] d = Stdio.file_get_bytes(fn); d = Stdio.AESDec2(key, iv, d); J.WipeRam(key); J.WipeRam(iv); key = null; iv = null; return Stdio.MxDaccuShifter(d, Magic); } public void DBG(String M) { System.out.print("DBG: " + this.getClass().getSimpleName() + "\t " + M + "\n"); } public static void EXC(Exception E, String dove) { echo("\n\nException: " + dove + " = " + E.toString() + "\n" + E.getMessage() + "\n" + E.getLocalizedMessage() + "\n"); StackTraceElement[] S = E.getStackTrace(); for (int ax = 0; ax < S.length; ax++) echo("STACK " + ax + ":\t " + S[ax].toString() + "\n"); } protected static void ZZ_Exceptionale() throws Exception { throw new Exception(); } //Remote version verify }