001package net.minecraft.util;
002
003import cpw.mods.fml.common.asm.ReobfuscationMarker;
004import cpw.mods.fml.relauncher.Side;
005import cpw.mods.fml.relauncher.SideOnly;
006import java.io.InputStream;
007import java.io.OutputStream;
008import java.io.UnsupportedEncodingException;
009import java.nio.charset.Charset;
010import java.security.InvalidKeyException;
011import java.security.Key;
012import java.security.KeyFactory;
013import java.security.KeyPair;
014import java.security.KeyPairGenerator;
015import java.security.MessageDigest;
016import java.security.NoSuchAlgorithmException;
017import java.security.PrivateKey;
018import java.security.PublicKey;
019import java.security.SecureRandom;
020import java.security.Security;
021import java.security.spec.InvalidKeySpecException;
022import java.security.spec.X509EncodedKeySpec;
023import javax.crypto.BadPaddingException;
024import javax.crypto.Cipher;
025import javax.crypto.IllegalBlockSizeException;
026import javax.crypto.NoSuchPaddingException;
027import javax.crypto.SecretKey;
028import javax.crypto.spec.SecretKeySpec;
029import org.bouncycastle.crypto.BufferedBlockCipher;
030import org.bouncycastle.crypto.CipherKeyGenerator;
031import org.bouncycastle.crypto.KeyGenerationParameters;
032import org.bouncycastle.crypto.engines.AESFastEngine;
033import org.bouncycastle.crypto.io.CipherInputStream;
034import org.bouncycastle.crypto.io.CipherOutputStream;
035import org.bouncycastle.crypto.modes.CFBBlockCipher;
036import org.bouncycastle.crypto.params.KeyParameter;
037import org.bouncycastle.crypto.params.ParametersWithIV;
038import org.bouncycastle.jce.provider.BouncyCastleProvider;
039
040@ReobfuscationMarker
041public 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}