    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 cipherkeygenerator = new CipherKeyGenerator();
    054        cipherkeygenerator.init(new KeyGenerationParameters(new SecureRandom(), 128));
    055        return new SecretKeySpec(cipherkeygenerator.generateKey(), "AES");
    056    }
    057
    058    public static KeyPair createNewKeyPair()
    059    {
    060        try
    061        {
    062            KeyPairGenerator keypairgenerator = KeyPairGenerator.getInstance("RSA");
    063            keypairgenerator.initialize(1024);
    064            return keypairgenerator.generateKeyPair();
    065        }
    066        catch (NoSuchAlgorithmException nosuchalgorithmexception)
    067        {
    068            nosuchalgorithmexception.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 unsupportedencodingexception)
    084        {
    085            unsupportedencodingexception.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 messagedigest = MessageDigest.getInstance(par0Str);
    098            byte[][] abyte = par1ArrayOfByte;
    099            int i = par1ArrayOfByte.length;
    100
    101            for (int j = 0; j < i; ++j)
    102            {
    103                byte[] abyte1 = abyte[j];
    104                messagedigest.update(abyte1);
    105            }
    106
    107            return messagedigest.digest();
    108        }
    109        catch (NoSuchAlgorithmException nosuchalgorithmexception)
    110        {
    111            nosuchalgorithmexception.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 x509encodedkeyspec = new X509EncodedKeySpec(par0ArrayOfByte);
    124            KeyFactory keyfactory = KeyFactory.getInstance("RSA");
    125            return keyfactory.generatePublic(x509encodedkeyspec);
    126        }
    127        catch (NoSuchAlgorithmException nosuchalgorithmexception)
    128        {
    129            nosuchalgorithmexception.printStackTrace();
    130        }
    131        catch (InvalidKeySpecException invalidkeyspecexception)
    132        {
    133            invalidkeyspecexception.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 illegalblocksizeexception)
    176        {
    177            illegalblocksizeexception.printStackTrace();
    178        }
    179        catch (BadPaddingException badpaddingexception)
    180        {
    181            badpaddingexception.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 cipher = Cipher.getInstance(par1Str);
    196            cipher.init(par0, par2Key);
    197            return cipher;
    198        }
    199        catch (InvalidKeyException invalidkeyexception)
    200        {
    201            invalidkeyexception.printStackTrace();
    202        }
    203        catch (NoSuchAlgorithmException nosuchalgorithmexception)
    204        {
    205            nosuchalgorithmexception.printStackTrace();
    206        }
    207        catch (NoSuchPaddingException nosuchpaddingexception)
    208        {
    209            nosuchpaddingexception.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 bufferedblockcipher = new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 8));
    222        bufferedblockcipher.init(par0, new ParametersWithIV(new KeyParameter(par1Key.getEncoded()), par1Key.getEncoded(), 0, 16));
    223        return bufferedblockcipher;
    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}