消息摘要算法

作者: Mr_魏 | 来源:发表于2017-08-18 16:09 被阅读0次

    消息摘要算法

    友情提示,本文档的图床使用极简图床进行图片存储,默认存储到七牛云空间

    本文档依赖的jar maven地址如下:

    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.10</version>
    </dependency>
    
     <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.57</version>
    </dependency>
    

    分类名词解释

    • MD
      message Digest 消息摘要
    • SHA
      Secure hash algorithm安全散列
    • MAC
      message authenttication code 消息认证码

    三个名词的作用

    验证数据的完整性(比如maven仓库的md5数据完整性比对)

    消息摘要算法是数字签名的核心算法

    MD算法分类

    • MD5
    • MD家族(生成都是128位摘要信息 如果md2,md4)

    MD算法特点

    单项加密 不可逆

    MD5的实现方

    package com.ztgeo.secret;
    
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    import org.apache.commons.codec.binary.Hex;
    
    public class MDDemo {
        
    //md家族的加解密算法
    
    private static String reqStr= "MD5需要加密的数据";
    
    public static void main(String[] args) {
        secretMD5();
    }
    
    
    public static void secretMD5(){
        try {
            //使用原生jdk就可以进行md5的加密
            MessageDigest md = MessageDigest.getInstance("MD5");
            //进行消息摘要(md5加密)
            byte[] md5Bytes =md.digest(reqStr.getBytes());
            System.out.println("md5加密后未经转换的byte[]后的结果:"+md5Bytes);  
            System.out.println("md5加密后转换成string后的结果:"+new String(md5Bytes));    
            //转换后的长度没有128 只有11位 就算转换成string也是如下乱码:������'�?9�O��s4
            //所以md5加密后的数据 不能直接使用 应该使用16进制转换后的结果作为加密结果  
            
            //恰巧bc和cc中都有该功能的方法 一般选择cc中方法  
            
            System.out.println("转换成16进制之后的加密数组:"+Hex.encodeHexString(md5Bytes));
            
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        
    }
    
    }
    

    该算法 也同样支持md2 只需要在获得实例的时候传入"MD2"即可
    但是jdk没有提供md4的实现 强制使用md4获得实例会报错

    使用bc实现md4或者其他加密方式

    private static void BCMD4(){
        //使用bc包实现md4的算法 加密  
        Digest digest = new MD4Digest();
        //预处理 md4需要加密的字符串(类似读取 输入流)
        digest.update(reqStr.getBytes(), 0,reqStr.getBytes().length);
        //使用byte数组去接收结果 相当于处理完了 用容器去承载结果  
        byte[] md4Byte = new byte[digest.getDigestSize()];
        ///读出到输入流
        digest.doFinal(md4Byte, 0);
        //这个时候结果容器被装满  使用bc自带的64位转码进行转码  
        System.out.println("BC加密后的MD4加密结果:"+org.bouncycastle.util.encoders.Hex.toHexString(md4Byte));
    
    }
    

    当然 也可以用cc去实现相同的功能 只是在cc中并没有提供md4的实现,猜测cc只是简化辅助jdk的md功能 没有做功能的延伸

    //使用cc实现md的加密
    //如果看源码会发现 实际上cc并没有去自己写md的实现 只是引用来了jdk的md相应实现
    public static void ccMD5(){
        //这里需要提的而是 cc实现 md5的方法中 有个方法简化了hex转化64位的操作
        System.out.println("CCmd5的简单实现:"+DigestUtils.md5Hex(reqStr.getBytes()));
    }
    

    md算法的总结

    • 使用jdk的方法是偏底层的,不提供16进制转换
    • bc的优势在于提供了md4的实现(jdk和cc没有)
    • cc实现了hex进制转换的直接使用 但只是简化了jdk的方法 没有自己实现

    md加密方式的应用

    注册时用户名明文 密码变为不可逆 密文 存入数据库
    登录时用户名明文 密码直接拿去数据库比对
    这样有效的防止了信息泄露(就算拿到数据库还是不知道密码)

    SHA

    • 安全散列算法
    • 固定长度的摘要信息
    • 很多场景下 被称为md5的继承者
    • 美国国家安全局设计的(背景强大)
    • 由MD4演变而来
    • 内容稍有不同结果就大相径庭 很难被破译

    SHA的分类

    • SHA-1
    • SHA-2
      • SHA-224
      • SHA-256
      • SHA-384
      • SHA-512

    算法的实现


    依然没有cc的算法.是因为cc又是对jdk的简化操作

    SHA的算法应用

    防止数据传输过程中被篡改,保证数据的完整性
    常用的传输方式是在url上传参 并发送sha的消息摘要,,对方进行消息摘要的对比 看传输数据是否发生了篡改

    MAC

    • 兼容了md和sha的特性
    • 加入了秘钥(hmac 含有秘钥的sha算法)

    MAC的分类

    • MD系列

      • HmacMD2
      • HmacMD4
      • HmacMD5
    • SHA系列

      • HmacSHA1
      • HmacSHA2
        • HmacSHA224
        • HmacSHA256
        • HmacSHA384
        • HmacSHA512

    MAC算法的摘要长度和实现方

    MAC的代码实现

    package com.ztgeo.secret;
    
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    
    import javax.crypto.KeyGenerator;
    import javax.crypto.Mac;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    
    import org.apache.commons.codec.DecoderException;
    import org.bouncycastle.crypto.digests.MD5Digest;
    import org.bouncycastle.crypto.macs.HMac;
    import org.bouncycastle.crypto.params.KeyParameter;
    import org.bouncycastle.util.encoders.Hex;
    
    public class MacDemo {     
    //mac安全散列算法的实现(有秘钥)
    
    private static String reqStr="需要被mac摘要的数据";
    
    public static void main(String[] args) {
        jdkHmacMD5();
        bHmacMD5();
    }
    
    public static void jdkHmacMD5(){
        
        try {
            //获得秘钥工厂  
            KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
            
            //一下两步是是随机生产key  但实际情况 需要制定key
            /*//生成秘钥  
            SecretKey key = keyGenerator.generateKey();
            //获得秘钥
            byte[] keyByte = key.getEncoded();*/
            
            byte[] keyByte = org.apache.commons.codec.binary.Hex.decodeHex(new char[]{'a','a','a','a','a','a','a','a','a','a'});
            
            //还原秘钥 数组秘钥 通过类进行还原
            SecretKey restoreKey = new SecretKeySpec(keyByte, "HmacMD5");
            //实例化MAC 使用秘钥还原
            Mac mac = Mac.getInstance(restoreKey.getAlgorithm());
            //初始化mac
            mac.init(restoreKey);
            //执行加密(摘要) 
            byte[] HmacMd5Bytes = mac.doFinal(reqStr.getBytes());
            //输出摘要的结果
            System.out.println("jkd hmacMD5结果:"+Hex.toHexString(HmacMd5Bytes));
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (DecoderException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    
    //bc实现mac md5算法  
    public static void bHmacMD5(){
        //实例化mac
        HMac hmac = new HMac(new MD5Digest());
        //初始化mac
        hmac.init(new KeyParameter(Hex.decode("aaaaaaaaaa")));
        //读入流
        hmac.update(reqStr.getBytes(),0,reqStr.getBytes().length);
        
        //准备容器 
        byte[] hmacMD5Bytes = new byte[hmac.getMacSize()];
        
        //放置输出结果
        hmac.doFinal(hmacMD5Bytes, 0);
        
        //输出结果
        System.out.println("bcHmacMD5结果:"+Hex.toHexString(hmacMD5Bytes));
        
    }
    
    }
    

    对称加密算法

    加密秘钥和解密秘钥相同

    对称加密算法的特点

    • 初等的加密算法(安全级别不高)
    • DES(代表性的加密算法,长度不够 安全性低 已被破解)
      • 3DES
    • AES(替代DES)
    • PBE
    • IDEA

    DES详解

    出身

    ibm提交美国,98年后被破解,目前不具备安全性

    实现方式和实现方

    使用jdk实现DES算法的加解密

        package com.ztgeo.secret;
    
    import java.security.Key;
    import java.security.NoSuchAlgorithmException;
    
    import javax.crypto.Cipher;
    import javax.crypto.KeyGenerator;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.DESKeySpec;
    
    import org.apache.commons.codec.binary.Hex;
    
    public class DESDemo {
    
    private static String reqStr ="需要被加密内容!!";
    
    public static void main(String[] args) {
            jdkDES();
    }
    
    public static void jdkDES(){
        
        try {
            //生成秘钥材料
            /*KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
            //指定秘钥长度  DES是56位
            keyGenerator.init(56);
            SecretKey key = keyGenerator.generateKey();
            //获得程序产生的key
            byte[] keyByte = key.getEncoded();*/
            
            
            //当然 可以自己指byte数组类型的秘钥
            byte[] keyByte = "15062101243".getBytes();      //秘钥
            
            
            //秘钥材料转换 
            DESKeySpec desKeySpec = new DESKeySpec(keyByte);
            
            //生成真正的key
            //实例化秘钥工厂(指定加密方式)
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
            Key convertSecretKey = factory.generateSecret(desKeySpec);
        
            //加密 (需要填充加解密的算法/工作方式/填充方式) 
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            //加密模式ENCRYPT_MODE 和转换可以使用的key
            cipher.init(cipher.ENCRYPT_MODE, convertSecretKey);
            //执行加密操作
            byte[] result = cipher.doFinal(reqStr.getBytes());
            System.out.println("使用JDK加密DES:"+Hex.encodeHexString(result));
            
            //解密操作
            //依然使用cipher进行解密 需要的秘钥 也需要秘钥转换 
            cipher.init(cipher.DECRYPT_MODE, convertSecretKey);
            //执行加密操作 结果转成string
            result = cipher.doFinal(result);
            System.out.println("使用JDK解密DES:"+new String(result));
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
    //bc的DES实现 可以通过secret添加provide进行实现 实现方式和jdk类似 这里不做赘述 
    
    }
    

    3DES(三重DES)

    三重DES的必要性

    • DES违反了柯克霍夫原则(算法半公开) 所以安全性不高
    • DES的背景是美国安全局,所以是否有后门 不敢确保

    三重DES的好处

    • 密码长度增强
    • 迭代次数增多

    长度和实现方

    JDK的实现

    package com.ztgeo.secret;
    
    import java.security.Key;
    import java.security.SecureRandom;
    
    import javax.crypto.Cipher;
    import javax.crypto.KeyGenerator;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.DESedeKeySpec;
    
    import org.apache.commons.codec.binary.Hex;
    
    public class DES3 {
    
    private static String reqStr ="需要被加密内容!!";
    
    public static void main(String[] args) {
                jdk3des();
    }
    
    public static void jdk3des(){
        //jdk的三重des和des实现都是类似的 我们直接copy代码  
        try {
            //生成秘钥材料
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
            //指定秘钥长度 3DES是168位
            //keyGenerator.init(168);
            //当然 如果不想记什么算法多少位  可以使用根据getInstance对字符串变能量获得默认长度的秘钥  
            keyGenerator.init(new SecureRandom());
            SecretKey key = keyGenerator.generateKey();
            //获得程序产生的key
            byte[] keyByte = key.getEncoded();
            
            
            //当然 可以自己指byte数组类型的秘钥 但目前报错 原因未知
            //byte[] keyByte = "15062101243".getBytes();      //秘钥
            
            
            //秘钥材料转换 
            DESedeKeySpec desKeySpec = new DESedeKeySpec(keyByte);
            
            //生成真正的key
            //实例化秘钥工厂(指定加密方式)
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
            Key convertSecretKey = factory.generateSecret(desKeySpec);
        
            //加密 (需要填充加解密的算法/工作方式/填充方式) 
            Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
            //加密模式ENCRYPT_MODE 和转换可以使用的key
            cipher.init(cipher.ENCRYPT_MODE, convertSecretKey);
            //执行加密操作
            byte[] result = cipher.doFinal(reqStr.getBytes());
            System.out.println("使用JDK加密3DES:"+Hex.encodeHexString(result));
            
            //解密操作
            //依然使用cipher进行解密 需要的秘钥 也需要秘钥转换 
            cipher.init(cipher.DECRYPT_MODE, convertSecretKey);
            //执行加密操作 结果转成string
            result = cipher.doFinal(result);
            System.out.println("使用JDK解密3DES:"+new String(result));
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
        
    }
    
    }
    

    AES

    AES的产生原因

    • DES安全性不要
    • 3DES效率不高
    • AES是DES(包括3DES的替代品)
    • 对称加密的首选就是AES 使用率最高
    • AES目前官方并没有确认被破解

    AES的应用范围

    AES用于移动通讯系统加密以及基于SSH协议的软件

    算法实现

    jdk的实现(bc的实现和aes十分类似 不举例了)

    package com.ztgeo.secret;
    
    import java.security.Key;
    import java.security.NoSuchAlgorithmException;
    
    import javax.crypto.Cipher;
    import javax.crypto.KeyGenerator;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    
    import org.apache.commons.codec.binary.Base64;
    
    public class AESDemo {
    
    private static String reqStr ="需要被加密内容!!";
    
    public static void main(String[] args) {
        jdkAes();
    }
    
    
    public static void jdkAes(){
        try {
            //生成key
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(128);
            SecretKey sekey = keyGenerator.generateKey();
            //获得程序产生的key
            byte[] keyByte = sekey.getEncoded();
            
            //转换key
            Key key  = new SecretKeySpec(keyByte, "AES");
            
            //加密  填充
            Cipher  cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] resultByte = cipher.doFinal(reqStr.getBytes());
            System.out.println("AES加密后的内容(base64之后):"+Base64.encodeBase64String(resultByte));
            
            
            
            //解密
            cipher.init(Cipher.DECRYPT_MODE, key);
            resultByte = cipher.doFinal(resultByte);
            System.out.println("使用JDK解密AES操作:"+new String(resultByte));
            
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
    }
    
    
    } 
    

    对称加密算法之----PBE

    • pbe算法结合了消息摘要算法和对称加密算法的所有优点
    • pbe(password based encryption)基于口令的加密
    • 只是对已有算法的包装
    • JDK,BC
    • 盐(秘钥口令和扰码)
    • 是一种综合性算法(消息摘要+对称加密) 常见 PBEWithMD5AndDES

    PBE算法的实现

    演示jdk实现PBE的算法

    package com.ztgeo.secret;
    
    import java.security.Key;
    import java.security.SecureRandom;
    
    import javax.crypto.Cipher;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.PBEKeySpec;
    import javax.crypto.spec.PBEParameterSpec;
    
    import org.apache.commons.codec.binary.Base64;
    
    
    public class PBEDemo {
    
    private static String reqStr = "需要被加密的内容";
    
    public static void main(String[] args) {
            jdkPBE();
    }
    
    public static void jdkPBE(){
        try {
            //初始化盐 盐可以理解为随机数  
            SecureRandom random = new SecureRandom();
            //用8位 产生盐
            byte[] salt =  random.generateSeed(8);
    
            
            //口令转秘钥
            String password = "12345687";
            //密码转换成口令秘钥  
            PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHMD5andDES");
            Key key = factory.generateSecret(pbeKeySpec);
            
            //加密
            
            //将盐构成params
            PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 100);
            Cipher cipher  = Cipher.getInstance("PBEWITHMD5andDES");
            cipher.init(Cipher.ENCRYPT_MODE, key,parameterSpec);
            byte[] byteResult = cipher.doFinal(reqStr.getBytes());
            System.out.println("jdk使用PBE加密后的结果:"+ Base64.encodeBase64String(byteResult));
            
            //解密
            
            cipher.init(Cipher.DECRYPT_MODE,key,parameterSpec);//秘钥 盐
            byteResult = cipher.doFinal(byteResult);
            System.out.println("jdk使用PBE解密后的结果:"+ new String(byteResult));
            } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    
        
        
    }
    
    }
    

    PBE在的实际使用

    由图中可以看出,解谜.不仅要知道解密的秘钥,还要知道加密时实时产生的随机数才能正确解密,极大提高了数据性;

    非对称加密算法

    因为对称加密算法是双方秘钥相同.所以又叫做初等加密算法

    非对称加密算法的特点

    • 高级加密算法(秘钥不对称)
    • 双保险(类似vip银行客户保险柜原理.银行一把钥匙.客户一把钥匙)
    • 公钥,私钥 (都是成对出现的)

    非对称加密的分类

    • DH(Diffie-Hellman)密钥交换算法
    • RSA-基于因子分解(三个人姓氏开头,应用最广)
    • ElGamal-基于离散对数
    • ECC(椭圆曲线加密)

    DH加密算法

    • 非对称加密的鼻祖
    • 是为了解决对称加密算法密钥的传输安全级别低的问题应运而生的
    • 构建本地秘钥 解决秘钥传递的问题

    DH相关实现方

    JDK实现加密算法使用类

    加密方:

    • KeyPairGenerator 秘钥对的 生产类
    • KeyPair 秘钥对 可以产生公钥和私钥
    • PublicKey 公钥

    解密方:

    • KeyFactory 秘钥工厂(根据规范生成公钥私钥) 还原秘钥
    • X509EncodeKeySpec 根据ASN.1进行秘钥编码
    • DHPublicKey
    • DHParameterSpec DH算法中 参数的集合类
    • KeyPairGenerator
    • PrivateKey

    秘钥构建
    KeyAgreement 提供秘钥协议的类
    SecretKey 秘密秘钥 生成分组的秘密秘钥

    加密,解密
    Cipher 加密解密 提供密码功能类

    DH加密的步骤

    1. 发送方发送公钥载体
    2. 接收方根据发送方公钥产生接收方公钥载体
    3. 根据接受方公钥载体产生本地秘钥
    4. 发送接收方公钥载体
    5. 接收方根据接收方的公钥载体 产生本地秘钥
    6. 对比双方本地秘钥 完全相同后发送方根据本地秘钥加密数据
    7. 接收方 根据本地秘钥进行 解密数据

    在此过程中,双方的本地秘钥不同,但两次发送,彼此依赖生成,形成完美的闭环,具体代码如下:

    package com.ztgeo.secret;
    
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.NoSuchAlgorithmException;
    import java.security.PublicKey;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.Objects;
    
    import javax.crypto.Cipher;
    import javax.crypto.KeyAgreement;
    import javax.crypto.SecretKey;
    import javax.crypto.interfaces.DHPublicKey;
    import javax.crypto.spec.DHParameterSpec;
    
    import org.apache.commons.codec.binary.Base64;
    
    //非对称加密 
    public class DHDemo {
    private static String reqStr = "需要被加密的数据123456";
    
    public static void main(String[] args) {
        try {
        //1.初始化发送方的秘钥   
            
            //钥匙对工厂产生钥匙对
            KeyPairGenerator sendKeyPairGenerator = KeyPairGenerator.getInstance("DH");
            sendKeyPairGenerator.initialize(512);
            //钥匙对 用来存放公钥和私钥
            KeyPair sendKeyPair =sendKeyPairGenerator.generateKeyPair();
            //获得公钥载体 发送给接收方 (网络,文件...)
            byte[] sendPublicKeyEnc = sendKeyPair.getPublic().getEncoded();
            
            
        //2.初始化接收方秘钥 推算出 公钥 
            KeyFactory reciverKeyFactory  = KeyFactory.getInstance("DH");
            //秘钥标准
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(sendPublicKeyEnc);
            //通过标准和 公钥载体 获得公钥
            PublicKey reciverPublicKey = reciverKeyFactory.generatePublic(x509EncodedKeySpec);
            //获得公钥参数 用来构建钥匙对
            DHParameterSpec dhParameterSpec = ((DHPublicKey)reciverPublicKey).getParams();
            
            //从发送方载体中获得了公钥参数 可以构建 参数对了
            KeyPairGenerator receiverKeyPairGenerator = KeyPairGenerator.getInstance("DH");
            receiverKeyPairGenerator.initialize(dhParameterSpec);
            KeyPair receiverKeyPair = receiverKeyPairGenerator.generateKeyPair();
            //接收方 公钥载体
            byte[] receiverPublicKeyEnc = receiverKeyPair.getPublic().getEncoded();
            
        //3.秘钥构建(私钥)  具体可分为 发送方的私钥构建 和接收方的 私钥构建
            //接受方
            KeyAgreement receviverKeyAgreement = KeyAgreement.getInstance("DH");
            //使用私钥进行初始化
            receviverKeyAgreement.init(receiverKeyPair.getPrivate());
            receviverKeyAgreement.doPhase(reciverPublicKey, true);
            //本地私钥产生 并发送
            SecretKey receiverDesKey = receviverKeyAgreement.generateSecret("DES");
        
            //发送方(根据接收方 第一次返回的公钥载体进行生成私钥 并反推成本地秘钥)
            KeyFactory senderKeyFactory = KeyFactory.getInstance("DH");
            x509EncodedKeySpec = new X509EncodedKeySpec(receiverPublicKeyEnc);
            PublicKey senderPublicKey = senderKeyFactory.generatePublic(x509EncodedKeySpec);
            KeyAgreement senderKeyAgreement = KeyAgreement.getInstance("DH");
            senderKeyAgreement.init(sendKeyPair.getPrivate());
            senderKeyAgreement.doPhase(senderPublicKey, true);
            SecretKey senderDesKey = senderKeyAgreement.generateSecret("DES");
        
            //接收方 根据发送方私钥产生了 本地秘钥  
            //发送方 也根据接收方传过来的 公钥 产生了本地秘钥 
            
            //验证 双方本地秘钥是否相同  
            if(Objects.equals(receiverDesKey, senderDesKey)){
                System.out.println("验证成功,双方产生的本地秘钥相同!!");
            }
            
        //4.加密数据 
            //发送方根据 本地 私钥 加密数据  
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, senderDesKey);
            byte[] result = cipher.doFinal(reqStr.getBytes());
            System.out.println("使用DH加密的数据是:"+Base64.encodeBase64String(result));
            
        //5.客户端解密数据  
            //接收方根据 本地秘钥进行解密
            cipher.init(Cipher.DECRYPT_MODE, receiverDesKey);
            result = cipher.doFinal(result);
            System.out.println("使用DH解密后的数据是:"+new String(result));
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        }
    
    }
    

    具体实现的流程图如下:

    流程模板分析

    1、甲方(消息发送方,下同)构建密钥对(公钥+私钥),甲方公布公钥给乙方(消息接收方,下同)

    2、乙方以甲方发送过来的公钥作为参数构造密钥对(公钥+私钥),将构造出来的公钥公布给甲方

    3、甲方用“甲方的私钥+乙方的公钥”构造本地密钥

    4、乙方用“乙方的私钥+甲方的公钥”构造本地的密钥

    5、这个时候,甲乙两方本地新构造出来的密钥应该一样。然后就可以使用AES这类对称加密算法结合密钥进行数据的安全传送了。传送过程参考AES的相关算法

    DH加密算法较为复杂,进一步学习可以参考这篇博客
    http://blog.csdn.net/kongqz/article/details/6302913

    非对称加密算法-RSA

    • 唯一广泛接受并实现
    • 可用于数据加密&数字签名
    • 公钥加密,私钥解密
    • 私钥加密,公钥解密

    RSA长度和填充及是实现方式

    具体实现:

    package com.ztgeo.secret;
    
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.NoSuchAlgorithmException;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    
    import javax.crypto.Cipher;
    
    import org.apache.commons.codec.binary.Base64;
    
    import com.sun.org.apache.xml.internal.security.encryption.CipherData;
    
    public class RSADemo {
    
    private static String reqStr = "需要被加解密的字符串!!12345689";
    
    public static void main(String[] args) {
        jdkRSA();
    }
    
    public static void jdkRSA(){
        try {
        //1.初始化秘钥  
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(512);
            //公钥 私钥
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
            RSAPrivateKey rasPrivateKey = (RSAPrivateKey)keyPair.getPrivate();
            System.out.println("公钥:"+Base64.encodeBase64String(rsaPublicKey.getEncoded()));
            System.out.println("私钥:"+Base64.encodeBase64String(rasPrivateKey.getEncoded()));
        //2.使用私钥加密
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rasPrivateKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);//私钥加密
            byte[] result = cipher.doFinal(reqStr.getBytes());
            System.out.println("RSA私钥加密后的结果:"+Base64.encodeBase64String(result));
            
        //3.发送发 发送公钥 接收方使用公钥解密 密文  
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
            keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            result = cipher.doFinal(result);
            System.out.println("公钥解密的结果是:"+new String(result));
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    }
    

    公钥加密.私钥解密

    相关文章

      网友评论

        本文标题:消息摘要算法

        本文链接:https://www.haomeiwen.com/subject/lpuarxtx.html