zoukankan      html  css  js  c++  java
  • Java Web项目RSA加密

    最近做的一个项目,服务器为Java,采用SSH框架,客户端为Android和IOS。当用户登录时,从客户端向服务器提交用户名和密码。这就存在一个问题,如果数据包在网络上被其他人截取了,密码就有可能泄露。

    可以采用Base64对密码编码,但是Base64要进行解码是很容易的事。

    另一种方法是对密码进行MD5加密,MD5是不可逆的,只能加密不能解密。但是其他人截取了密码的MD5字符串以后,可以原封不动的将MD5加密后的字符串提交给服务器,服务器肯定会判断这是正确的密码,这样还是可以登录进去。

    解决的方法就只能采用加密算法了。加密算法分为对称加密和非对称加密。对称加密算法,加密和解密使用相同的密钥,密钥在网络传输的过程中有可能被截取,所以不是很安全。非对称加密,使用公钥加密,只能使用私钥解密,公钥是公开的,私钥是不公开的。即使在传递的过程中,公钥被其他人获取了也无所谓,因为公钥是用来加密的,只有私钥才能解密,而私钥是不会传递的,也就不可能被其他人获取。

    非对称加密最常用的就是RSA算法,RSA算法是由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的,取了他们姓的第一个字母来命名。RSA算法的原理就不讲了。密钥长度为768的RSA算法有可能被破解,密钥长度为1024的RSA算法还没有被破解,所以可以认为密钥长度为1024的RSA算法是比较安全的。但是RSA算法的计算量大,一般只用于关键信息的加密,如密码、对称加密算法的密钥等。在我们的项目中,就使用RSA算法对用户密码进行加密。具体的步骤如下:

    1. 客户端向服务器申请密钥;

    2. 服务器接收到客户端的申请以后,生成一对密钥,将公钥发给客户端,私钥自己保存;

    3. 客户端接收到公钥以后,使用公钥对密码加密,然后将密文发给服务器;

    4. 服务器接收到密文以后,使用私钥解密,判断是否是正确的密码。

    下面是关键代码。

    生成密钥和加密、解密的代码:

    /** 
         * 生成公钥和私钥 
         * @throws NoSuchAlgorithmException  
         * 
         */  
        public static HashMap<String, Object> getKeys() throws NoSuchAlgorithmException{  
            HashMap<String, Object> map = new HashMap<String, Object>();  
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");  
            keyPairGen.initialize(1024);  
            KeyPair keyPair = keyPairGen.generateKeyPair();  
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();  
            map.put("public", publicKey);  
            map.put("private", privateKey);  
            return map;  
        } 
        
        /** 
         * 使用模和指数生成RSA公钥 
         * 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA 
         * /None/NoPadding】 
         *  
         * @param modulus 
         *            模 
         * @param exponent 
         *            指数 
         * @return 
         */  
        public static RSAPublicKey getPublicKey(String modulus, String exponent) {  
            try {  
                BigInteger b1 = new BigInteger(modulus);  
                BigInteger b2 = new BigInteger(exponent);  
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
                RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);  
                return (RSAPublicKey) keyFactory.generatePublic(keySpec);  
            } catch (Exception e) {  
                e.printStackTrace();  
                return null;  
            }  
        }  
      
        /** 
         * 使用模和指数生成RSA私钥 
         * 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA 
         * /None/NoPadding】 
         *  
         * @param modulus 
         *            模 
         * @param exponent 
         *            指数 
         * @return 
         */  
        public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {  
            try {  
                BigInteger b1 = new BigInteger(modulus);  
                BigInteger b2 = new BigInteger(exponent);  
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
                RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);  
                return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);  
            } catch (Exception e) {  
                e.printStackTrace();  
                return null;  
            }  
        }  
      
        /** 
         * 公钥加密 
         *  
         * @param data 
         * @param publicKey 
         * @return 
         * @throws Exception 
         */  
        public static String encryptByPublicKey(String data, RSAPublicKey publicKey)  
                throws Exception {  
            Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");  
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
            // 模长  
            int key_len = publicKey.getModulus().bitLength() / 8;  
            // 加密数据长度 <= 模长-11  
            String[] datas = splitString(data, key_len - 11);  
            String mi = "";  
            //如果明文长度大于模长-11则要分组加密  
            for (String s : datas) {  
                mi += bcd2Str(cipher.doFinal(s.getBytes()));  
            }  
            return mi;  
        }  
      
        /** 
         * 私钥解密 
         *  
         * @param data 
         * @param privateKey 
         * @return 
         * @throws Exception 
         */  
        public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey)  
                throws Exception {  
            Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");  
            cipher.init(Cipher.DECRYPT_MODE, privateKey);  
            //模长  
            int key_len = privateKey.getModulus().bitLength() / 8;  
            byte[] bytes = data.getBytes();  
            byte[] bcd = ASCII_To_BCD(bytes, bytes.length);  
            System.err.println(bcd.length);  
            //如果密文长度大于模长则要分组解密  
            String ming = "";  
            byte[][] arrays = splitArray(bcd, key_len);  
            for(byte[] arr : arrays){  
                ming += new String(cipher.doFinal(arr));  
            }  
            return ming;  
        } 

    服务器收到客户端的请求时,生成一对密钥:

                    HashMap<String, Object> mymap = RSAUtils.getKeys();
                    // 生成公钥和私钥  
                    RSAPublicKey publicKey = (RSAPublicKey) mymap.get("public");  
                    RSAPrivateKey privateKey = (RSAPrivateKey) mymap.get("private"); 
                    //
                    String modulus = publicKey.getModulus().toString();  
                    // 公钥指数  
                    String public_exponent = publicKey.getPublicExponent().toString();  
                    // 私钥指数  
                    String private_exponent = privateKey.getPrivateExponent().toString(); 
                    // 使用模和指数生成公钥和私钥  
                    RSAPublicKey pubKey = RSAUtils.getPublicKey(modulus, public_exponent);  
                    RSAPrivateKey priKey = RSAUtils.getPrivateKey(modulus, private_exponent);

    将其中的模和私钥指数发给客户端,客户端收到以后,使用getPublicKey(String modulus, String exponent)生成公钥,使用公钥对密码加密,然后发给服务器。服务器收到密文以后,使用decryptByPrivateKey(String data, RSAPrivateKey privateKey)解密,获得密码明文,然后就可以判断密码是否正确。

  • 相关阅读:
    MySQL DELAY_KEY_WRITE Option
    More on understanding sort_buffer_size
    myisam_sort_buffer_size vs sort_buffer_size
    share-Nothing原理
    GROUP_CONCAT(expr)
    Mysql History list length 值太大引起的问题
    Why is the ibdata1 file continuously growing in MySQL?
    洛谷1201 贪婪的送礼者 解题报告
    洛谷1303 A*B Problem 解题报告
    洛谷2142 高精度减法 解题报告
  • 原文地址:https://www.cnblogs.com/mstk/p/5502110.html
Copyright © 2011-2022 走看看