• 对称加密与非对称加密


    对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法。有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,同时解密密钥也可以从加密密钥中推算出来。而在大多数的对称算法中,加密密钥和解密密钥是相同的,所以也称这种加密算法为秘密密钥算法或单密钥算法。它要求发送方和接收方在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都可以对他们发送或接收的消息解密,所以密钥的保密性对通信性至关重要。

    特点 

    对称加密算法的特点是算法公开、计算量小、加密速度快、加密效率高。
    不足之处是,交易双方都使用同样钥匙,安全性得不到保证。此外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的惟一钥匙,这会使得发收信双方所拥有的钥匙数量呈几何级数增长,密钥管理成为用户的负担。对称加密算法在分布式网络系统上使用较为困难,主要是因为密钥管理困难,使用成本较高。而与公开密钥加密算法比起来,对称加密算法能够提供加密和认证却缺乏了签名功能,使得使用范围有所缩小。在计算机专网系统中广泛使用的对称加密算法有DES和IDEA等
     
    算法
    DES算法3DES算法,TDEA算法,Blowfish算法,RC5算法,IDEA算法。
     
    附上代码(生成密钥及加密、解密)
     
    public static void desSecret() throws NoSuchAlgorithmException {
    
            // 密钥生成器
            KeyGenerator key = KeyGenerator.getInstance("DESede");
            /**
             * 初始化密钥生成器 该步骤一般指定密钥的长度。如果该步骤省略的话, 会根据算法自动使用默认的密钥长度。指定长度时,
             * 若第一步密钥生成器使用的是“DES”算法,则密钥长度必须是56位;
             * 若是“DESede”,则可以是112或168位,其中112位有效;若是“AES”, 可以是128,
             * 192或256位;若是“Blowfish”,则可以是32至448之间可以被8整除的数;
             * “HmacMD5”和“HmacSHA1”默认的密钥长度都是64个字节
             */
            key.init(168);
            // 生成密钥
            SecretKey secret = key.generateKey();
            FileOutputStream s;
            try {
                s = new FileOutputStream("D://des-pri.key");
                ObjectOutputStream st = new ObjectOutputStream(s);
                st.writeObject(secret);
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
        public static byte[] desEncrypt(String str) throws Exception {
            byte[] miby = null;
            FileInputStream s = new FileInputStream("D://des-pri.key");
            ObjectInputStream st = new ObjectInputStream(s);
            SecretKey secret = (SecretKey) st.readObject();
            // 工厂模式获取Cipher实例 密码器
            Cipher cp = Cipher.getInstance("DESede");
            // 初始化cipher ENCRYPT_MODE表示加密DECRYPT_MODE解密 后面一个参数是密钥
            cp.init(Cipher.ENCRYPT_MODE, secret);
            byte[] by = str.getBytes("utf-8");
            // 对字节码机密 miby就是加密后的字节码
            miby = cp.doFinal(by);
            return miby;
        }
    
        public static String desUnEncrypt(byte[] sct) throws Exception {
            // 通过提供的密钥文件 获取密钥对象 进行解密
            FileInputStream s = new FileInputStream("D://des-pri.key");
            ObjectInputStream st = new ObjectInputStream(s);
            SecretKey secret = (SecretKey) st.readObject();
            // 工厂模式获取Cipher实例 密码器
            Cipher cp = Cipher.getInstance("DESede");
            // 初始化cipher ENCRYPT_MODE表示加密DECRYPT_MODE解密 后面一个参数是密钥
            cp.init(Cipher.DECRYPT_MODE, secret);
    
            // 对密文字节码进行解密 如果密码写入文件可以使用文件流读写成一个数组
            byte[] miby = cp.doFinal(sct);
            // 获取密文字符串
            String minwen = new String(miby, "utf-8");
            return minwen;
        }

    非对称加密:非对称加密算法需要两个密钥公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥

    特点

    非对称加密与对称加密相比,其安全性更好:对称加密的通信双方使用相同的秘钥,如果一方的秘钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对秘钥,一个用来加密,一个用来解密,而且公钥是公开的,秘钥是自己保存的,不需要像对称加密那样在通信之前要先同步秘钥。
    非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
     
    算法
    RSAElgamal、Rabin、D-H、ECC
     
     
       工作的时候有对接银行接口,整理下关于RSA加密,双方通讯如何保证数据的安全 (RSA + 数字签名)
       
           一般通讯的双方交换对方公钥, 各方持有本方的公私钥、与对方的公钥  (私钥只有本人持有)
            通讯:
                   定义报文格式 :  128签名+加密报文
                   A通讯B
                       1. A用B的公钥加密明文,加密后的报文用A的私钥签名,组成报文发送B(报文约定格式)
            2. B根据约定的报文格式获取加密的密文与签名,通过B的私钥解密获取明文、A的公钥验证签名(加密数据)  
         
    场景
     
      数字签名原理
    1. A通过使用B的公钥加密数据后发给B,B利用B的私钥解密就得到了需要的数据(进过B公钥加密的数据只有B的私钥能够  
    2.   * 解开,C没有B的私钥,所以C解不开,但C可以使用B的公钥加密一份数据发给B,这样一来,问题来了,B收到的数据到  
    3.   * 底是A发过来的还是C发过来的呢)  
    4.   * 由于私钥是唯一的,那么A就可以利用A自己的私钥进行加密,然后B再利用A的公钥来解密,就可以确定:一定是A的消息,数字签名的原理就基于此

         A想将目标数据传给B,此时A需要准备1和2两部分    

    1. A使用B的公钥将原始信息加密,以起到保密作用(只有B的私钥能解开,其他人使用其他钥匙都解不开,当然就保密咯)  
    2. A使用A的私钥将原始信息的摘要进行签名,以起到接收方B确定是A发过来的作用(A用A的私钥对目标数据的摘要进行签名,然后传给B,同时,C用C的私钥对任意信息进行签名也传给B,B想接受的是A的数据(比如说一个转帐请求),于是B 就通过A的公钥对接受到的两个信息进行解密,解开的就是A(A的公钥能且只能解开A的私钥加密的数据))
    附上代码(生成非对称公私钥及加密、解密 + 数字签名)
     
      
     public static final String KEY_ALGORITHM = "RSA";  
        public static final String SIGNATURE_ALGORITHM = "MD5withRSA";  
      
        
        // 初始化RSA非对称密钥
        public static void generaterA() {
            try {
                KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
                SecureRandom secrand = new SecureRandom();
                keygen.initialize(1024, secrand);
                KeyPair keys = keygen.genKeyPair();
                PublicKey pubkey = keys.getPublic();
                PrivateKey prikey = keys.getPrivate();
                
                String strpk = new String(Base64.encodeBase64(pubkey.getEncoded()));  
                String strprivk = new String(Base64.encodeBase64(prikey.getEncoded()));
        
                DesSecretUtil.saveData(strpk.getBytes(), "D://rsa-pub_A.pem");
                DesSecretUtil.saveData(strprivk.getBytes(), "D://rsa-pri_A.pem");
                
            } catch (java.lang.Exception e) {
                System.out.println("生成密钥对失败");
                e.printStackTrace();
            }
        }  
        
        /** 
         * 用私钥对信息生成数字签名 
         *  
         * @param data 
         *            加密数据 
         * @param privateKey 
         *            私钥 
         *  
         * @return 
         * @throws Exception 
         */  
        
        public static String sign(byte[] data, String privateKey) throws Exception {  
            // 解密由base64编码的私钥  
            byte[] keyBytes = Base64.decodeBase64(privateKey);  
      
            // 构造PKCS8EncodedKeySpec对象  
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
      
            // KEY_ALGORITHM 指定的加密算法  
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
      
            // 取私钥匙对象  
            PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);  
      
            // 用私钥对信息生成数字签名  
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initSign(priKey);  
            signature.update(data);  
            
         // 加密由base64编码的签名  
            return Base64.encodeBase64String(signature.sign());  
        }  
      
        /** 
         * 校验数字签名 
         *  
         * @param data 
         *            加密数据 
         * @param publicKey 
         *            公钥 
         * @param sign 
         *            数字签名 
         *  
         * @return 校验成功返回true 失败返回false 
         * @throws Exception 
         *  
         */  
        public static boolean verify(byte[] data, String publicKey, String sign)  
                throws Exception {
      
            // 解密由base64编码的公钥  
            byte[] keyBytes = Base64.decodeBase64(publicKey);
      
            // 构造X509EncodedKeySpec对象  
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);  
      
            // KEY_ALGORITHM 指定的加密算法  
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
      
            // 取公钥匙对象  
            PublicKey pubKey = keyFactory.generatePublic(keySpec);
      
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initVerify(pubKey);  
            signature.update(data);
      
            // 验证签名是否正常  
            return signature.verify(Base64.decodeBase64(sign));  
        }  
      
        /** 
         * 解密<br> 
         * 用私钥解密 
         *  
         * @param data 
         * @param key 
         * @return 
         * @throws Exception 
         */  
        public static byte[] decryptByPrivateKey(byte[] data, String key)  
                throws Exception {  
            
            // 对密钥解密  
            byte[] keyBytes = Base64.decodeBase64(key);
      
            // 取得私钥  
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
            Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);  
      
            // 对数据解密  
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());  
            cipher.init(Cipher.DECRYPT_MODE, privateKey);  
      
            return cipher.doFinal(data);  
        }  
      
        /** 
         * 解密<br> 
         * 用公钥解密 
         *  
         * @param data 
         * @param key 
         * @return 
         * @throws Exception 
         */  
        public static byte[] decryptByPublicKey(byte[] data, String key)  
                throws Exception {  
            // 对密钥解密  
            byte[] keyBytes = Base64.decodeBase64(key);
      
            // 取得公钥  
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);  
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
            Key publicKey = keyFactory.generatePublic(x509KeySpec);  
      
            // 对数据解密  
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());  
            cipher.init(Cipher.DECRYPT_MODE, publicKey);  
      
            return cipher.doFinal(data);  
        }  
      
        /** 
         * 加密<br> 
         * 用公钥加密 
         *  
         * @param data 
         * @param key 
         * @return 
         * @throws Exception 
         */  
        public static byte[] encryptByPublicKey(byte[] data, String key)  
                throws Exception {  
            // base64 解密公钥
            byte[] keyBytes = Base64.decodeBase64(key);
            X509EncodedKeySpec  x509Key = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key publicKey = keyFactory.generatePublic(x509Key);
            
             // 对数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());        
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
            
            return cipher.doFinal(data); 
        }  
      
        /** 
         * 加密<br> 
         * 用私钥加密 
         *  
         * @param data 
         * @param key 
         * @return 
         * @throws Exception 
         */  
        public static byte[] encryptByPrivateKey(byte[] data, String key)  
                throws Exception {  
            // 对密钥解密  
            byte[] keyBytes = Base64.decodeBase64(key);  
      
            // 取得私钥  
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
            Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);  
      
            // 对数据加密  
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());  
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);  
      
            return cipher.doFinal(data);  
        }  
           
        public static void main(String[] args) {
            // A向B发送数据
            try {
    
                byte[] pub_A = DesSecretUtil.readData("D://rsa-pub_A.pem");
    
                byte[] pri_A = DesSecretUtil.readData("D://rsa-pri_A.pem");
    
                byte[] pub_B = DesSecretUtil.readData("D://rsa-pub_B.pem");
    
                byte[] pri_B = DesSecretUtil.readData("D://rsa-pri_B.pem");
                
                String str = "开始测试";
                
                byte[] data = str.getBytes("UTF-8");
                
                //拿B的公钥加密
                byte[] encrptData = encryptByPublicKey(data, new String(pub_B));
                
                System.out.println("加密后Base64数据:"+Base64.encodeBase64String(encrptData));
                
                
                //拿B的私钥解密
                byte[] decrptData = decryptByPrivateKey(encrptData,new String(pri_B));
                
                System.out.println("解密后明文:"+new String(decrptData,"UTF-8"));
    
                
                
                // A的私钥数字签名
                String sign = sign(encrptData,new String(pri_A));
                
                // 加密由base64编码的签名  
                System.out.println("加密由base64编码的签名 :"+sign);            
                
                
                // A的公钥数字签名验证是否信息被篡改
                
                boolean flag = verify(decrptData,new String(pub_A),sign);
                        
                System.out.println("数字签名验证 :"+flag);
                            
                
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        }
     
     
     
     
  • 相关阅读:
    《我想进大厂》之mysql夺命连环13问
    抽象数据类型的表示与实现
    数据结构两个层次——逻辑结构和存储结构
    单链表的两种构造函数
    使用malloc函数或new运算符为链表结点分配内存空间
    基于Vue全家桶开发的前端组件管理平台
    JS菱形镂空
    JS使用for循环实现九九乘法表数字颜色不同
    JS——个人所得税
    JAVA常见关键字
  • 原文地址:https://www.cnblogs.com/ks-apper/p/5181463.html
Copyright © 2020-2023  润新知