pepperim.util.IMCrypt.java Source code

Java tutorial

Introduction

Here is the source code for pepperim.util.IMCrypt.java

Source

/******************************************************
 * Copyright (C) 2011 Anton Pirogov, Felix Wiemuth    *
 * Licensed under the GNU GENERAL PUBLIC LICENSE      *
 * See LICENSE or http://www.gnu.org/licenses/gpl.txt *
 ******************************************************/

package pepperim.util;

import pepperim.Main;
import org.apache.commons.codec.binary.Base64;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.IOException;
import java.util.Random;
import java.security.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;

/**
 * A class providing all cryptography-relevant functions.
 * @author Anton Pirogov <anton dot pirogov at googlemail dot com>
 */
public class IMCrypt {
    static final String HEXES = "0123456789abcdef";

    /**
     * Returns random hexadecimal digits. (for AES encryption please use {@link #AES_genKey()})
     * @param num Number of digits
     * @return the hexadecimal string
     */
    public static String randHex(int num) {
        Random prng = new Random();
        String ret = "";
        for (int i = 0; i < num; i++) {
            int ind = prng.nextInt(16);
            ret += HEXES.substring(ind, ind + 1);
        }
        return ret;
    }

    /**
     * @param data data to be encoded
     * @return encoded data string
     */
    public static String B64_Enc(byte[] data) {
        return new String(new Base64().encodeBase64(data));
    }

    /**
     * @param data data string to be decoded
     * @return decoded data
     */
    public static byte[] B64_Dec(String data) {
        return new Base64().decodeBase64(data);
    }

    /**
     * @param s hexadecimal string
     * @return binary data
     */
    public static byte[] hexToBin(String s) {
        byte[] b = new byte[s.length() / 2];
        for (int i = 0; i < b.length; i++) {
            int v = Integer.parseInt(s.substring(i * 2, (i * 2) + 2), 16);
            b[i] = (byte) v;
        }
        return b;
    }

    /**
     * @param raw binary data
     * @return hexadecimal string
     */
    public static String binToHex(byte[] raw) {
        if (raw == null) {
            return null;
        }
        final StringBuffer hex = new StringBuffer(2 * raw.length);
        for (final byte b : raw) {
            hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
        }
        return hex.toString();
    }

    /**
     * @param text String to be hashed
     * @return SHA512-hash
     */
    public static String SHA512(String text) {
        try {
            MessageDigest md;
            md = MessageDigest.getInstance("SHA-512");
            byte[] hash = new byte[40];
            md.update(text.getBytes("UTF-8"), 0, text.length());
            hash = md.digest();
            return binToHex(hash);
        }

        catch (NoSuchAlgorithmException ex) {
            Main.log(ex.getMessage());
            return "";
        } catch (UnsupportedEncodingException ex) {
            Main.log(ex.getMessage());
            return "";
        }
    }

    /**
     * Generates a random string to be used as AES encryption key
     * @return random AES encryption key
     */
    public static String AES_genKey() {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");

            kgen.init(128);
            SecretKey skey = kgen.generateKey();
            byte[] raw = skey.getEncoded();

            return binToHex(raw);

        } catch (NoSuchAlgorithmException e) {
            Main.log(e.getMessage());
            return "";
        }
    }

    /**
     * @param data data to be encrypted
     * @param key key to be used
     * @return Base64-encoded encrypted data
     */
    public static String AES_Enc(String data, String key) {
        try {
            SecretKeySpec skeySpec = new SecretKeySpec(hexToBin(key), "AES");

            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            return B64_Enc(cipher.doFinal(data.getBytes()));
        } catch (Exception e) {
            Main.log(e.getMessage());
            return "";
        }
    }

    /**
     * @param data data to be decrypted (Base64-encoded)
     * @param key key to be used
     * @return decrypted data
     */
    public static String AES_Dec(String data, String key) {
        try {
            SecretKeySpec skeySpec = new SecretKeySpec(hexToBin(key), "AES");

            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            return new String(cipher.doFinal(B64_Dec(data)));
        } catch (Exception e) {
            Main.log(e.getMessage());
            return "";
        }
    }

    /**
     * Generates a new 2048 bit RSA keypair.
     * @return String array containing: [Base64-encoded public key, Base64-encoded private key]
     */
    public static String[] RSA_genKeypair() {
        try {
            KeyPairGenerator pairgen = KeyPairGenerator.getInstance("RSA");
            SecureRandom random = new SecureRandom();
            pairgen.initialize(2048, random);
            KeyPair keyPair = pairgen.generateKeyPair();
            String[] keypair = new String[2];
            keypair[0] = B64_Enc(keyPair.getPublic().getEncoded());
            keypair[1] = B64_Enc(keyPair.getPrivate().getEncoded());
            return keypair;
        } catch (GeneralSecurityException e) {
            Main.log(e.getMessage());
            return null;
        }
    }

    /**
     * @param b64str Base64-encoded private key
     * @return PrivateKey object
     */
    public static PrivateKey decodePrivateKey(String b64str) {
        try {
            byte[] keydata = B64_Dec(b64str);
            PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(keydata);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            PrivateKey pk = kf.generatePrivate(ks);
            return pk;
        } catch (GeneralSecurityException e) {
            Main.log(e.getMessage());
            return null;
        }
    }

    /**
     * @param b64str Base64-encoded public key
     * @return PublicKey object
     */
    public static PublicKey decodePublicKey(String b64str) {
        try {
            byte[] keydata = B64_Dec(b64str);
            X509EncodedKeySpec ks = new X509EncodedKeySpec(keydata);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            PublicKey pk = kf.generatePublic(ks);
            return pk;
        } catch (GeneralSecurityException e) {
            Main.log(e.getMessage());
            return null;
        }
    }

    /**
     * RSA encryption. You can use a PrivateKey here, if you need a custom signing algorithm (otherwise you can use {@link #RSA_Sign(String,PrivateKey)})
     * @param data Data to be encrypted (should not be more than some dozen bytes!)
     * @param key Encryption key (PublicKey or PrivateKey)
     * @return Base64-encoded encrypted data
     */
    public static String RSA_Enc(String data, Key key) {
        try {
            Cipher c = Cipher.getInstance("RSA");
            c.init(Cipher.ENCRYPT_MODE, key);
            return B64_Enc(c.doFinal(data.getBytes()));
        } catch (GeneralSecurityException e) {
            Main.log(e.getMessage());
            return "";
        }
    }

    /**
     * @param data Base64-encoded encrypted data
     * @param key Decryption key (normally PrivateKey, but can also be PublicKey if you do custom signing)
     * @return decrypted data
     */
    public static String RSA_Dec(String data, Key key) {
        try {
            Cipher c = Cipher.getInstance("RSA");
            c.init(Cipher.DECRYPT_MODE, key);
            return new String(c.doFinal(B64_Dec(data)));
        } catch (GeneralSecurityException e) {
            Main.log(e.getMessage());
            return "";
        }
    }

    /**
     * Regular RSA signing (using SHA1-hash)
     * @param data Data to be signed
     * @param key Key to be used for the signature
     * @return Base64-encoded RSA signature
     */
    public static String RSA_Sign(String data, PrivateKey key) {
        try {
            Signature signer = Signature.getInstance("SHA1withRSA");
            signer.initSign(key);
            signer.update(data.getBytes());
            byte[] signature = signer.sign();
            return B64_Enc(signature);
        } catch (GeneralSecurityException e) {
            Main.log(e.getMessage());
            return "";
        }
    }

    /**
     * @param data Data to be verified
     * @param b64sig Base64-encoded RSA signature
     * @param key Public key of the signature source
     * @return true on success, false if the verification fails
     */
    public static boolean RSA_Verify(String data, String b64sig, PublicKey key) {
        try {
            Signature verifier = Signature.getInstance("SHA1withRSA");
            verifier.initVerify(key);
            verifier.update(data.getBytes());
            return verifier.verify(B64_Dec(b64sig));
        } catch (GeneralSecurityException e) {
            Main.log(e.getMessage());
            return false;
        }
    }
}