Java常见加密使用和分析

Java常见加密使用和分析

最近项目里碰到很多加解密的场景,使用多种加密的方式,大概整理了一下,一共有一下几种

加密方式安全性是否可逆
1MD5不可逆
2AES可逆
3RSA可逆
4Base64可逆

1.MD5加密

MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法)

MD5的一般在项目中的使用场景是密码加密,在校验密码时直接比较加密后的密文,对于这种不需要解密和展示的字段我们可以直接采用MD5的方式进行加密。MD5的本质就是将数据进行hash取得数据摘要,在一定程度上来说,MD5是无法被破解的。当然也可以通过撞库的方式来进行尝试破解,这个投入成本也是非常大的。为了避免撞库的命中率,还可以对MD5进行加盐。投入不同的随机字符串与数据进行拼接,亦或者在hash完的数据进行&运算。降低MD5撞库破解的威胁性。


Java中的使用MD5

public class MD5Util {

    //默认盐
    public static String LOCAL_SALT = "23543dfggeelysdafaqj23ou89ZXcj@#$@#$#@KJdjklj;D../dSF.,";

    //md5加密类
    private static MessageDigest md5;

    static {
        try {
            //获取md5实例
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    /**
     * MD5加密
     * @param data
     * @return
     */
    public static String encrypt(String data){
        //md5加密
        return byteArrayToHexString(md5.digest(data.getBytes()));
    }

    /**
     * MD5加盐加密
     * @param data
     * @param salt
     * @return
     */
    public static String encrypt(String data,String salt){
        //加盐
        data +=salt;
        //md5加密
        return byteArrayToHexString(md5.digest(data.getBytes()));
    }

    //这里主要是遍历8个byte,转化为16位进制的字符,即0-F
    private static String byteArrayToHexString(byte[] b) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            resultSb.append(byteToHexString(b[i]));
        }
        return resultSb.toString();
    }


    //这里是针对单个byte,256的byte通过16拆分为d1和d2
    private static String byteToHexString(byte b) {
        int n = b;
        if(n < 0) {
            n += 256;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
}

java中获取到MessageDigest的md5实例后就可以完成MD5加密。

2.AES加密

高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。也就是我们常说的对称密钥加密,加密和解密用相同的密钥。

加密原理:轮密钥加实际是一种Vernam密码形式,其本身不难被破解。另外三个阶段一起提供了混淆、扩散和非线性功能。这三个阶段没有涉及密钥,就它们自身而言,并未提供算法的安全性。然而,该算法经历一个分组的XOR加密(轮密钥加),再对该分组混淆扩散(其他三个阶段),再接着又是XOR加密,如此交替进行,这种方式非常有效非常安全。

可逆原理:每个阶段均可逆。对字节代替、行移位和列混淆,在解密算法中用它们相对应的逆函数。轮密钥加的逆就是用同样的轮密钥和分组相异或,其原理就是A⊕B⊕B = A。和大多数分组密码一样,AES解密算法按逆序利用扩展密钥,然而其解密算法和加密算法并不一样,这是由AES的特定结构决定的。图5.3中加密和解密流程在纵向上是相反的,在每个水平点上,state数组在加密和解密函数中都是一样的。

AES加密的使用场景一般是在敏感信息在数据传输过程,微信小程序使用的AES加密传输数据。因为AES加解使用的是同一个密钥,AES可逆,如果密钥泄露也就意味着数据可以被解密。数据在频繁传输过程中,可能需要动态变更密钥来保证数据传输的安全性。


Java中AES加密

/**
 * AES对称密钥加解密
 */
public class AESUtil {

    /**
     * 生成AES密钥
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String generateKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("RSA");
        //初始化生成器
        keyGenerator.init(1024, new SecureRandom());
        //生成AES密钥
        SecretKey secretKey = keyGenerator.generateKey();
        byte[] keyByte = secretKey.getEncoded();
        return HexBin.encode(keyByte);
    }

    /**
     * 生成AES密钥
     * @param keySize 密钥最大长度
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String generateKey(Integer keySize) throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("RSA");
        //初始化生成器
        keyGenerator.init(keySize, new SecureRandom());
        //生成AES密钥
        SecretKey secretKey = keyGenerator.generateKey();
        byte[] keyByte = secretKey.getEncoded();
        return HexBin.encode(keyByte);
    }

    /**
     * AES加密
     * @param str
     * @param secreKey
     * @return
     * @throws Exception
     */
    public static String encrypt( String str, String secreKey ) throws Exception{
        //密钥
        Key key  = new SecretKeySpec(HexBin.decode(secreKey),"AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        //初始化加密
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] result = cipher.doFinal(str.getBytes());
       return HexBin.encode(result);
    }

    /**
     * AES解密
     * @param str
     * @param secreKey
     * @return
     * @throws Exception
     */
    public static String decrypt(String str,String secreKey)  throws Exception{
        Key key  = new SecretKeySpec(HexBin.decode(secreKey),"AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        //初始化解密
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] result = cipher.doFinal(str.getBytes());
        return new String(result);

    }
}

java中的AES的加密完全依赖 Cipher类。RSA加解密使用也是这个类。

3.RSA加密

RSA是一种非对称加密算法。现在,很多登陆表单的密码的都采用RSA加密,例如京东中的登陆使用公钥对密码进行加密。

RSA这个加密算法就是经常听到非对称密钥加密,顾名思义,RSA加解密使用的不是同一个密钥,RSA中存在两个密钥,一个是公钥,一个是私钥,公钥暴露给数据发送端,私钥在数据接收端保留,数据发送端在数据传输前使用公钥加密数据,数据接受端在接收到数据时使用私钥解密,拿到真实数据。来保证数据传输的安全性。
RSA主要使用大整数分解这个数学难题进行设计,巧妙地利用了数论的概念,如今,只有短的 RSA 密钥才有可能被强力方式解破。长度足够长的密钥是安全系数时很高的。


Java中RSA加密

/**
 * RSA加解密工具类
 * @author machenike
 */
public class RASUtil {

    /**
     * 密钥对存储场所
     */
    private static KeyStore keyStore = new LocalKeyStore();

    /**
     * 当前线程持有的公钥
     */
    private static ThreadLocal<String> currentPublicKey = new ThreadLocal<>();

    /**
     * 生成RSA密钥对
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String[] generateKeyPair(){
        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            e.printStackTrace();
            return null;
        }
        // 初始化密钥对生成器,密钥大小为96-1024位
        keyPairGen.initialize(1024,new SecureRandom());
        // 生成一个密钥对,保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 得到私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 得到公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
        // 得到私钥字符串
        String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
        // 将公钥和私钥保存到String数组
        String[] result = new String[2];
        result[0] = publicKeyString;
        result[1] = privateKeyString;
        return result;
    }

    /**
     * 生成RSA密钥对
     * @param keySize 密钥最大长度
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String[] generateKeyPair(Integer keySize){
        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
        // 初始化密钥对生成器,密钥大小为96-1024位
        keyPairGen.initialize(keySize,new SecureRandom());
        // 生成一个密钥对,保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        /* 得到私钥 */
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 得到公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
        // 得到私钥字符串
        String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
        // 将公钥和私钥保存到String数组
        String[] result = new String[2];
        result[0] = publicKeyString;
        result[1] = privateKeyString;
        return result;
    }

    /**
     * RSA公钥加密
     *
     * @param str
     *            加密字符串
     * @param publicKey
     *            公钥
     * @return 密文
     * @throws Exception
     *             加密过程中的异常信息
     */
    public static String encrypt( String str, String publicKey ) throws Exception{
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
        return outStr;
    }

    /**
     * 使用私钥进行RSA解密
     *
     * @param str
     *            加密字符串
     * @param privateKey
     *            私钥
     * @return 铭文
     * @throws Exception
     *             解密过程中的异常信息
     */
    public static String decrypt(String str, String privateKey) throws Exception{
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = Base64.decodeBase64(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }

    /**
     * 通过当前的线程的公钥进行RSA私钥解密
     *
     * @param str
     *            加密字符串
     *            私钥
     * @return 铭文
     * @throws Exception
     *             解密过程中的异常信息
     */
    public static String decrypt(String str) throws Exception{
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = Base64.decodeBase64(keyStore.getPrivateKey(currentPublicKey.get()));
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }

    /**
     * 获取当前线程得公共键
     * @param currentPublicKey
     */
    public static void setCurrentPublicKey(String currentPublicKey){
        RASUtil.currentPublicKey.set(currentPublicKey);
    }

    /**
     * 设定存储密钥的实现
     * @param keyStore
     */
    public static void setKeyStore(KeyStroke keyStore){
        keyStore = keyStore;
    }
}

使用KeyPairGenerator生成密钥对,同时服务端会将公钥返回到客户端,客户端是RSA进行加密,而私钥保存在系统内部,不对外暴露,收到数据时使用cipher进行解密。保证数据传输的安全性,就算数据被抓包抓到,只要数据没有经过后台,那么数据就是无法解密。

4.Base64加密

Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读

其实base64不算是一种加密方式,只能说是一种特定的编码方式,目的是为了方便数据传输。比如图片可以转成base64字符串进行传输,接收完数据后,在进行base64解码就可把图片还原出来。


Java中Base64

/**
 * Base64解码编码工具类
 */
public class Base64Util {

    //解码器
    private static final Base64.Decoder decoder = Base64.getDecoder();
    //编码器
    private static final Base64.Encoder encoder = Base64.getEncoder();

    /**
     * Base64编码
     * @param data
     * @return
     */
    public static String encode(String data){
        return encoder.encodeToString(data.getBytes());
    }

    /**
     * Base64解码
     * @param data
     * @return
     */
    public static String decode(String data){
        return new String(decoder.decode(data.getBytes()));
    }
}

上面所有的常用方法我都已经整理集成到我的安全包里。
https://github.com/DavidLei08/s-encrypt.git

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值