zoukankan      html  css  js  c++  java
  • 对称加密与非对称加密

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

    特点 

    对称加密算法的特点是算法公开、计算量小、加密速度快、加密效率高。
    不足之处是,交易双方都使用同样钥匙,安全性得不到保证。此外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的惟一钥匙,这会使得发收信双方所拥有的钥匙数量呈几何级数增长,密钥管理成为用户的负担。对称加密算法在分布式网络系统上使用较为困难,主要是因为密钥管理困难,使用成本较高。而与公开密钥加密算法比起来,对称加密算法能够提供加密和认证却缺乏了签名功能,使得使用范围有所缩小。在计算机专网系统中广泛使用的对称加密算法有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();
            }
            
        }
     
     
     
     
  • 相关阅读:
    896. Monotonic Array单调数组
    865. Smallest Subtree with all the Deepest Nodes 有最深节点的最小子树
    489. Robot Room Cleaner扫地机器人
    JavaFX
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
  • 原文地址:https://www.cnblogs.com/ks-apper/p/5181463.html
Copyright © 2011-2022 走看看