001    package net.minecraft.util;
002    
003    import cpw.mods.fml.common.asm.ReobfuscationMarker;
004    import cpw.mods.fml.relauncher.Side;
005    import cpw.mods.fml.relauncher.SideOnly;
006    import java.io.InputStream;
007    import java.io.OutputStream;
008    import java.io.UnsupportedEncodingException;
009    import java.nio.charset.Charset;
010    import java.security.InvalidKeyException;
011    import java.security.Key;
012    import java.security.KeyFactory;
013    import java.security.KeyPair;
014    import java.security.KeyPairGenerator;
015    import java.security.MessageDigest;
016    import java.security.NoSuchAlgorithmException;
017    import java.security.PrivateKey;
018    import java.security.PublicKey;
019    import java.security.SecureRandom;
020    import java.security.Security;
021    import java.security.spec.InvalidKeySpecException;
022    import java.security.spec.X509EncodedKeySpec;
023    import javax.crypto.BadPaddingException;
024    import javax.crypto.Cipher;
025    import javax.crypto.IllegalBlockSizeException;
026    import javax.crypto.NoSuchPaddingException;
027    import javax.crypto.SecretKey;
028    import javax.crypto.spec.SecretKeySpec;
029    import org.bouncycastle.crypto.BufferedBlockCipher;
030    import org.bouncycastle.crypto.CipherKeyGenerator;
031    import org.bouncycastle.crypto.KeyGenerationParameters;
032    import org.bouncycastle.crypto.engines.AESFastEngine;
033    import org.bouncycastle.crypto.io.CipherInputStream;
034    import org.bouncycastle.crypto.io.CipherOutputStream;
035    import org.bouncycastle.crypto.modes.CFBBlockCipher;
036    import org.bouncycastle.crypto.params.KeyParameter;
037    import org.bouncycastle.crypto.params.ParametersWithIV;
038    import org.bouncycastle.jce.provider.BouncyCastleProvider;
039    
040    @ReobfuscationMarker
041    public class CryptManager
042    {
043        /** ISO_8859_1 */
044        public static final Charset charSet = Charset.forName("ISO_8859_1");
045    
046        @SideOnly(Side.CLIENT)
047    
048        /**
049         * Generate a new shared secret AES key from a secure random source
050         */
051        public static SecretKey createNewSharedKey()
052        {
053            CipherKeyGenerator var0 = new CipherKeyGenerator();
054            var0.init(new KeyGenerationParameters(new SecureRandom(), 128));
055            return new SecretKeySpec(var0.generateKey(), "AES");
056        }
057    
058        public static KeyPair createNewKeyPair()
059        {
060            try
061            {
062                KeyPairGenerator var0 = KeyPairGenerator.getInstance("RSA");
063                var0.initialize(1024);
064                return var0.generateKeyPair();
065            }
066            catch (NoSuchAlgorithmException var1)
067            {
068                var1.printStackTrace();
069                System.err.println("Key pair generation failed!");
070                return null;
071            }
072        }
073    
074        /**
075         * Compute a serverId hash for use by sendSessionRequest()
076         */
077        public static byte[] getServerIdHash(String par0Str, PublicKey par1PublicKey, SecretKey par2SecretKey)
078        {
079            try
080            {
081                return digestOperation("SHA-1", new byte[][] {par0Str.getBytes("ISO_8859_1"), par2SecretKey.getEncoded(), par1PublicKey.getEncoded()});
082            }
083            catch (UnsupportedEncodingException var4)
084            {
085                var4.printStackTrace();
086                return null;
087            }
088        }
089    
090        /**
091         * Compute a message digest on arbitrary byte[] data
092         */
093        private static byte[] digestOperation(String par0Str, byte[] ... par1ArrayOfByte)
094        {
095            try
096            {
097                MessageDigest var2 = MessageDigest.getInstance(par0Str);
098                byte[][] var3 = par1ArrayOfByte;
099                int var4 = par1ArrayOfByte.length;
100    
101                for (int var5 = 0; var5 < var4; ++var5)
102                {
103                    byte[] var6 = var3[var5];
104                    var2.update(var6);
105                }
106    
107                return var2.digest();
108            }
109            catch (NoSuchAlgorithmException var7)
110            {
111                var7.printStackTrace();
112                return null;
113            }
114        }
115    
116        /**
117         * Create a new PublicKey from encoded X.509 data
118         */
119        public static PublicKey decodePublicKey(byte[] par0ArrayOfByte)
120        {
121            try
122            {
123                X509EncodedKeySpec var1 = new X509EncodedKeySpec(par0ArrayOfByte);
124                KeyFactory var2 = KeyFactory.getInstance("RSA");
125                return var2.generatePublic(var1);
126            }
127            catch (NoSuchAlgorithmException var3)
128            {
129                var3.printStackTrace();
130            }
131            catch (InvalidKeySpecException var4)
132            {
133                var4.printStackTrace();
134            }
135    
136            System.err.println("Public key reconstitute failed!");
137            return null;
138        }
139    
140        /**
141         * Decrypt shared secret AES key using RSA private key
142         */
143        public static SecretKey decryptSharedKey(PrivateKey par0PrivateKey, byte[] par1ArrayOfByte)
144        {
145            return new SecretKeySpec(decryptData(par0PrivateKey, par1ArrayOfByte), "AES");
146        }
147    
148        @SideOnly(Side.CLIENT)
149    
150        /**
151         * Encrypt byte[] data with RSA public key
152         */
153        public static byte[] encryptData(Key par0Key, byte[] par1ArrayOfByte)
154        {
155            return cipherOperation(1, par0Key, par1ArrayOfByte);
156        }
157    
158        /**
159         * Decrypt byte[] data with RSA private key
160         */
161        public static byte[] decryptData(Key par0Key, byte[] par1ArrayOfByte)
162        {
163            return cipherOperation(2, par0Key, par1ArrayOfByte);
164        }
165    
166        /**
167         * Encrypt or decrypt byte[] data using the specified key
168         */
169        private static byte[] cipherOperation(int par0, Key par1Key, byte[] par2ArrayOfByte)
170        {
171            try
172            {
173                return createTheCipherInstance(par0, par1Key.getAlgorithm(), par1Key).doFinal(par2ArrayOfByte);
174            }
175            catch (IllegalBlockSizeException var4)
176            {
177                var4.printStackTrace();
178            }
179            catch (BadPaddingException var5)
180            {
181                var5.printStackTrace();
182            }
183    
184            System.err.println("Cipher data failed!");
185            return null;
186        }
187    
188        /**
189         * Creates the Cipher Instance.
190         */
191        private static Cipher createTheCipherInstance(int par0, String par1Str, Key par2Key)
192        {
193            try
194            {
195                Cipher var3 = Cipher.getInstance(par1Str);
196                var3.init(par0, par2Key);
197                return var3;
198            }
199            catch (InvalidKeyException var4)
200            {
201                var4.printStackTrace();
202            }
203            catch (NoSuchAlgorithmException var5)
204            {
205                var5.printStackTrace();
206            }
207            catch (NoSuchPaddingException var6)
208            {
209                var6.printStackTrace();
210            }
211    
212            System.err.println("Cipher creation failed!");
213            return null;
214        }
215    
216        /**
217         * Create a new BufferedBlockCipher instance
218         */
219        private static BufferedBlockCipher createBufferedBlockCipher(boolean par0, Key par1Key)
220        {
221            BufferedBlockCipher var2 = new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 8));
222            var2.init(par0, new ParametersWithIV(new KeyParameter(par1Key.getEncoded()), par1Key.getEncoded(), 0, 16));
223            return var2;
224        }
225    
226        public static OutputStream encryptOuputStream(SecretKey par0SecretKey, OutputStream par1OutputStream)
227        {
228            return new CipherOutputStream(par1OutputStream, createBufferedBlockCipher(true, par0SecretKey));
229        }
230    
231        public static InputStream decryptInputStream(SecretKey par0SecretKey, InputStream par1InputStream)
232        {
233            return new CipherInputStream(par1InputStream, createBufferedBlockCipher(false, par0SecretKey));
234        }
235    
236        static
237        {
238            Security.addProvider(new BouncyCastleProvider());
239        }
240    }