zoukankan      html  css  js  c++  java
  • Java加密与解密笔记(一) Base64和数据摘要算法

    对加密解密下面的内容一定要先理解:

    甲乙双方要通信,中间的连接可能被人窃听甚至篡改。解决办法就是把传输的内容进行加密,用密文去传输,这样即使被监听也没办法知道信息的具体内容。

    加密时,甲乙双方可以约定一个密码A,甲用A加密,乙用A解密,这就是对称加密。对称加密的一个问题是:密钥怎么传递给对方?

    貌似没解,于是就出现了非对称加密,非对称加密时有两个密钥,就是公钥也私钥。用公钥加密的只能用私钥解密,反之用私钥加密的则只能用公钥解密。这样在流程上有点儿变化了。

    原先在对称加密中,密钥没法传递,现在好了,密钥不用传递,因为公钥是公开的,谁都可以拿到。流程如下:

    1. 甲要给乙发送信息,那么甲需要知道乙的公钥;
    2. 甲用乙的公钥进行加密,将数据传递给乙;
    3. 乙用自己的私钥进行解密,从而获得数据

    过程中:

    1. 如果有人窃听到了数据,因为这个人没有乙的私钥,所以没法解密,所以查看不到数据内容;
    2. 如果有人想篡改数据呢?答案也做不到,因为连甲发的什么内容都不知道所以就谈不上篡改了。

    这里有点儿要注意的细节是,甲要发送数据时,不是自己造公钥,而是问接收方要公钥。

    上述过程中还漏掉了一个问题:虽然篡改不了问题,那我总可以冒名发数据吧?

    因为乙的公钥是公开的,那我就可以拿着乙的公钥给乙想发什么就发什么?

    乙怎么知道数据甲发过来的呢?答案是用数字签名来验证。

    非对称加密RSA就支持数字签名,流程是:

    1. 甲用自己的私钥个数据生成一个签名;
    2. 甲在给乙发送数据的时候,把签名也一并发送过去;
    3. 乙在收到数据的时候,用甲公布的公钥来验证接收到的签名;

     总的来说,对应于安全问题的解决办法如下:

    1. 数据完整性问题:数据摘要验证
    2. 数据保密性问题:对称加密&非对称加密
    3. 身份验证问题:数字签名

    简单数据转换

    Base64

    将数据转换为不便于识别的数据算是一种最简单的加密了,比如Base64编码:

    public class Base64Util {
        
        public static void main(String[] args) throws Exception{
            
            
            String str = "Hello";
            byte[] bytes = str.getBytes();
            String encodedStr = encode(bytes);
            System.out.println(encodedStr);
            
            byte[] decodedBytes = decode(encodedStr);
            System.out.println(new String(decodedBytes));
            
        }
        
        public static String encode(byte[] bytes){
            return new BASE64Encoder().encode(bytes);
        }
        
        public static byte[] decode(String encodeStr) throws IOException{
            return new BASE64Decoder().decodeBuffer(encodeStr);
        }
    
    }

    Java8内置Base64的实现,可以通过java.util.Base64工具类来使用。

    输出如下:

    SGVsbG8=
    
    Hello

    这种编码是可逆的,因此加密的数据越长,则得到的结果越长,因为数据中存储了所有原始数据的细节。另外一些,比如MD5算法,是不可逆的,则属于内容摘要,多长的数据拿过来,最终得到的摘要结果长度都是一样的。因为这个特性所以经常用于校验文件是否被修改过。

    数据摘要算法

    MD5

    public class MD5Util {
    
        public static void main(String[] args) throws Exception {
            MessageDigest md = MessageDigest.getInstance("MD5");
            String pwd = "a";
            
            byte[] md5Bytes = md.digest(pwd.getBytes("UTF-8"));
            System.out.println(new String(Hex.encode(md5Bytes)));
            System.out.println(Base64Util.encode(md5Bytes));
            
            
        }
    }

    MD5一般和Base64配合使用,用来加密得到固定长度的Base64码。如果不用Base64编码,Spring的Hex对MD5数据进行了友好的输出。

     MD是Message Digest Algorithm的简称,中文名消息摘要算法,目前最新为第五版即MD5,历史版本有MD4、MD2等,由于存在缺陷都已不再使用。消息摘要算法各个版本间的结果是不一样的。

    MD2算法产生于1989年;
    MD4算法产生于1990年;
    MD5算法产生于1991年。

    MD5是目前广泛使用的版本,不过其安全性多年前就开始被质疑(碰撞算法)。于是在2008年提出了MD6算法,其后MD6历经数次改进,目前还是试行方案阶段,未被正式使用。

    另外,从JDK的API来看,除了MDx家族外,还有其他一些消息摘要算法:

     SHA

    SHA的全称叫安全散列算法(Secure Hash Algorithm),它是比MD5更安全消息摘要算法。

    public class SHAUtil {
        public static void main(String[] args) throws Exception{
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            String str = "Hello";
            String str2 = Base64Util.encode(md.digest(str.getBytes()));
            System.out.println(str2);
        }
    }

    HMAC 

     HMAC的全称是哈希消息认证码(Hash Message Authentication Code)。个人觉得,所有的消息摘要无非是要做数据验证。一个重要的例子,我们不会在数据库中保存明文的用户密码,而保存密码的摘要。因为摘要算法是透明的,那么为了防止撞库,就需要在摘要时“加盐”。所加的盐其实也是有讲究的,随机数?当期系统时间?其实都很容易被猜测。HMAC正是来解决这个问题的。它不管具体的消息摘要是怎样的,既可以用MD5也可以用SHA。它关注的是怎样生成这个随机的盐,也就是密钥。在HMAC中,摘要时是需要秘钥的,从而保证了摘要的隐蔽性,因此不容易被撞库。

    public class HMACUtil {
    
        public static void main(String[] args) throws Exception {
            
            String data = "Hello";
            String key = getKey();
            System.out.println("key:" + key);
            
            String mac = encryptHmac(key.getBytes(), data.getBytes());
            System.out.println(mac);
            
            System.out.println(encryptHmac(key.getBytes(), "Hello2".getBytes()));
            
        }
        
        public static String getKey()throws Exception{
            KeyGenerator generator = KeyGenerator.getInstance("HmacMD5");
            SecretKey key = generator.generateKey();
            byte[] bytes = key.getEncoded();
            return Base64Util.encode(bytes);
        }
        
        public static String encryptHmac(byte[] key,byte[] data)throws Exception{
            SecretKey secretKey = new SecretKeySpec(key, "HmacMD5");
            Mac mac = Mac.getInstance("HmacMD5");
            mac.init(secretKey);
            
            byte[] resultBytes = mac.doFinal(data);
            String resultString = Base64Util.encode(resultBytes);
            return resultString;
        }
    }

     HMAC可用的摘要算法名称:

    加密解密领域到处都有“秘钥”(Key),索性JDK自己实现了生成很多算法的秘钥的方法(KeyGenerator ),这些算法包括:

     

    其他相关文章:
     
     

     参考资料:

    http://snowolf.iteye.com/blog/379860

  • 相关阅读:
    Python pymysql
    Zk 集群概念
    k8s教程
    Python 经典类和新式类
    Python 私有属性
    Python 高级面向对象
    Python 面向对象5 多态
    MyBatis学习总结(八)——Mybatis3.x与Spring4.x整合
    MyBatis学习总结(七)——Mybatis缓存
    MyBatis学习总结(六)——调用存储过程
  • 原文地址:https://www.cnblogs.com/at0x7c00/p/7519600.html
Copyright © 2011-2022 走看看