[轉載]加密解密算法【RSA、AES、DES、MD5】介紹和使用

為了防止我們的數據泄露,我們往往會對數據進行加密,特別是敏感數據,我們要求的安全性更高。下面將介紹幾種常用的加密算法使用。這些算法的加密對象都是基于二進制數據,如果要加密字符串就使用統一編碼(如:utf8)進行編碼后加密。

1.摘要算法

常用的摘要算法有MD5,SHA1。摘要算法是一個不可逆過程,就是無論多大數據,經過算法運算后都是生成固定長度的數據,一般結果使用16進制進行顯示。
MD5和SHA1的區別:MD5結果是128位摘要,SHa1是160位摘要。那么MD5的速度更快,而SHA1的強度更高。

下面統一使用MD5算法進行說明,SHA1類似。
主要用途有:驗證消息完整性,安全訪問認證,數據簽名。

  • 消息完整性:由于每一份數據生成的MD5值不一樣,因此發送數據時可以將數據和其MD5值一起發送,然后就可以用MD5驗證數據是否丟失、修改。
  • 安全訪問認證:這是使用了算法的不可逆性質,(就是無法從MD5值中恢復原數據)對賬號登陸的密碼進行MD5運算然后保存,這樣可以保證除了用戶之外,即使數據庫管理人員都無法得知用戶的密碼。
  • 數字簽名:這是結合非對稱加密算法和CA證書的一種使用場景。

一般破解方法:字典法,就是將常用密碼生成MD5值字典,然后反向查找達到破解目的,因此建議使用強密碼。

MD5的使用—對文件進行摘要。

    //對文件進行MD5摘要
    public static String getMD5(String path){

        String pathName = path;
        String md5= "";
        try {
            File file = new File(pathName);
            FileInputStream ins = new FileInputStream(file);
            FileChannel ch = ins.getChannel();
            MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,file.length());       
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(byteBuffer);
            ins.close();
            md5 = toHexString(md.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return md5;
    }

    //以16進制編碼進行輸出
    final static char hex[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    public static String toHexString(byte[] tmp){
        String s;
        char str[] = new char[tmp.length*2];
        int k =0;
        for (int i = 0; i < tmp.length; i++) {
            byte byte0 = tmp[i];
            str[k++] = hex[byte0>>>4&0xf];
            str[k++] = hex[byte0&0xf];
        }
        s=new String(str);
        return s;
    }

SHA1的使用


    //對文件進行SHA1摘要
    public static String getSHA1(String path){
        String pathName = path;
        String sha1= "";
        try {
            File file = new File(pathName);
            FileInputStream ins = new FileInputStream(file);
            FileChannel ch = ins.getChannel();
            MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,file.length());       
            MessageDigest sha = MessageDigest.getInstance("SHA-1");
            sha.update(byteBuffer);
            ins.close();
            sha1 = toHexString(sha.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sha1;
    }

可以發現我們的關鍵代碼就是

    MessageDigest sha = MessageDigest.getInstance("SHA-1");
    sha.update(byteBuffer);
    ins.close();
    byte[] r = sha.digest());

只是不同的算法初始化時不同罷了。MessageDigest.getInstance("SHA-1")
另外還可以使用

DigestUtils.sha1(data);
DigestUtils.md5Hex(data);

上面實現使用的是Apache下面的一個加解密開發包commons-codec
官方地址為:http://commons.apache.org/codec/
官方下載地址:http://commons.apache.org/codec/download_codec.cgi

2.對稱加密算法

對稱加密算法只是為了區分非對稱加密算法。其中鮮明的特點是對稱加密是加密解密使用相同的密鑰,而非對稱加密加密和解密時使用的密鑰不一樣。對于大部分情況我們都使用對稱加密,而對稱加密的密鑰交換時使用非對稱加密,這有效保護密鑰的安全。非對稱加密加密和解密密鑰不同,那么它的安全性是無疑最高的,但是它加密解密的速度很慢,不適合對大數據加密。而對稱加密加密速度快,因此混合使用最好。
常用的對稱加密算法有:AES和DES.

  • DES:比較老的算法,一共有三個參數入口(原文,密鑰,加密模式)。而3DES只是DES的一種模式,是以DES為基礎更安全的變形,對數據進行了三次加密,也是被指定為AES的過渡算法。
  • AES:高級加密標準,新一代標準,加密速度更快,安全性更高(不用說優先選擇)

AES的使用

AES密鑰長度可以選擇128位【16字節】,192位【24字節】和256位【32字節】密鑰(其他不行,因此別亂設密碼哦)。

    /**使用AES對字符串加密
     * @param str utf8編碼的字符串
     * @param key 密鑰(16字節)
     * @return 加密結果
     * @throws Exception
     */
    public static byte[] aesEncrypt(String str, String key) throws Exception { 
           if (str == null || key == null) return null; 
           Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
           cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "AES")); 
           byte[] bytes = cipher.doFinal(str.getBytes("utf-8")); 
           return  bytes;
       } 
    /**使用AES對數據解密
     * @param bytes utf8編碼的二進制數據
     * @param key 密鑰(16字節)
     * @return 解密結果
     * @throws Exception
     */
       public static String aesDecrypt(byte[] bytes, String key) throws Exception { 
           if (bytes == null || key == null) return null; 
           Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
           cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "AES")); 
           bytes = cipher.doFinal(bytes);
           return new String(bytes, "utf-8"); 
       } 

上面代碼是對字符串進行的加解密。但要注意的是AES算法的所有參數都是字節碼的(包括密鑰)。因此字符串字符需要轉換成字節碼后進行加密str.getBytes("utf-8")按照字符串的編碼進行轉換。另外參數:”AES/ECB/PKCS5Padding”在加密和解密時必須相同,可以直接寫”AES”,這樣就是使用默認模式(C#和java默認的模式不一樣,C#中默認的是這種,java的默認待研究)。分別的意思為:AES是加密算法,ECB是工作模式,PKCS5Padding是填充方式。
AES是分組加密算法,也稱塊加密。每一組16字節。這樣明文就會分成多塊。當有一塊不足16字節時就會進行填充。
一共有四種工作模式:

  • ECB 電子密碼本模式:相同的明文塊產生相同的密文塊,容易并行運算,但也可能對明文進行攻擊。
  • CBC 加密分組鏈接模式:一塊明文加密后和上一塊密文進行鏈接,不利于并行,但安全性比ECB好,是SSL,IPSec的標準。
  • CFB 加密反饋模式:將上一次密文與密鑰運算,再加密。隱藏明文模式,不利于并行,誤差傳遞。
  • OFB 輸出反饋模式:將上一次處理過的密鑰與密鑰運算,再加密。隱藏明文模式,不利于并行,有可能明文攻擊,誤差傳遞。

PKCS5Padding的填充方式是差多少字節就填數字多少;剛好每一不足16字節時,那么就會加一組填充為16.還有其他填充模式【Nopadding,ISO10126Padding】(不影響算法,加密解密時一致就行)。

DES的使用

和AES類似,指定為DES就行。3DES指定為”DESede”,DES密鑰長度是56位,3DES加長了密鑰長度,可以為112位或168位,所以安全性提高,速度降低。工作模式和填充模式標準和AES一樣。

    /**使用DES對字符串加密
     * @param str utf8編碼的字符串
     * @param key 密鑰(56位,7字節)
     * @return 加密結果
     * @throws Exception
     */
    public static byte[] desEncrypt(String str, String key) throws Exception { 
           if (str == null || key == null) return null; 
           Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); 
           cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "DES")); 
           byte[] bytes = cipher.doFinal(str.getBytes("utf-8")); 
           return  bytes;
       } 
    /**使用DES對數據解密
     * @param bytes utf8編碼的二進制數據
     * @param key 密鑰(16字節)
     * @return 解密結果
     * @throws Exception
     */
       public static String desDecrypt(byte[] bytes, String key) throws Exception { 
           if (bytes == null || key == null) return null; 
           Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); 
           cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "DES")); 
           bytes = cipher.doFinal(bytes);
           return new String(bytes, "utf-8"); 
       } 

3.非對稱加密(RSA)

這里主要對RSA進行介紹。
對稱加密加密解密使用的是相同的密鑰,而非對稱加密加密解密時使用的不同的密鑰,分為公鑰(public key)和私鑰(private key).公鑰可以公開,而私鑰自己保存。它利用的是兩個大質數相乘十分容易,而對其乘積進行因素分解十分困難。這樣就可以將乘積作為密鑰了,這個乘積為N值,根據兩個大質數選擇e和生成d,刪掉兩個大質數。這樣(N,e)為公鑰,(N,d)為私鑰,公鑰無法破解出私鑰(不作詳細介紹,我們不是研究算法的)。由于非對稱加密的密鑰生成麻煩,所以無法做到一次一密,而且其加密速度很慢,無法對大量數據加密。因此最常用的使用場景就是數字簽名和密碼傳輸,用作數字簽名時使用私鑰加密,公鑰解密;用作加密解密時,使用公鑰加密,私鑰解密。

需要注意的是RSA加密是有長度限制的,1024位密鑰可以加密128字節(1024位),不滿128字節的使用隨機數填充,但是RSA實現中必須要加隨機數(11字節以上),所以明文長度最大為117字節,然后剩下的加入隨機數。這也產生了每次加密結果每一次都不一樣的特點。

如果明文長度超過限制怎么辦?

  • 1.可以與對稱加密混合使用,一次一密產生對稱加密的密鑰,然后使用此密鑰進行數據對稱加密,再使用RSA私鑰對對稱密鑰加密,一起保存。解密時使用公鑰解密出密鑰,然后進行數據解密。
  • 2.可以分段加密。將明文按117字節分成多段,加密后再拼接起來。由于每一段密文長度都是128字節,所以解密時按照128字節分段解密。

java的RSA密鑰生成與使用

簡單使用

下面是java中的使用方法,先是生成密鑰對,然后加密,再解密。需要注意的是這個方法是不能跨語言使用的,因為里面對公鑰和私鑰用到的序列化是java的序列化。
由于加密后的密文都是字節碼形式的,我們要以字符串方式保存或傳輸的話,可以使用Base64編碼。

public class RSAUtil {
    /** 指定加密算法為RSA */
    private static String ALGORITHM = "RSA";
    /*指定加密模式和填充方式*/
    private static String ALGORITHM_MODEL = "RSA/ECB/PKCS1Padding";
    /** 指定key的大小,一般為1024,越大安全性越高 */
    private static int KEYSIZE = 1024;
    /** 指定公鑰存放文件 */
    private static String PUBLIC_KEY_FILE = "PublicKey";
    /** 指定私鑰存放文件 */
    private static String PRIVATE_KEY_FILE = "PrivateKey";

    /**
     * 生成密鑰對
     */
    private static void generateKeyPair() throws Exception {
        /** RSA算法要求有一個可信任的隨機數源 */
        SecureRandom sr = new SecureRandom();
        /** 為RSA算法創建一個KeyPairGenerator對象 */
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM);
        /** 利用上面的隨機數據源初始化這個KeyPairGenerator對象 */
        kpg.initialize(KEYSIZE, sr);
        /** 生成密匙對 */
        KeyPair kp = kpg.generateKeyPair();
        /** 得到公鑰 */
        Key publicKey = kp.getPublic();
        /** 得到私鑰 */
        Key privateKey = kp.getPrivate();
        /** 用對象流將生成的密鑰寫入文件 */
        ObjectOutputStream oos1 = new ObjectOutputStream(new FileOutputStream(
                PUBLIC_KEY_FILE));
        ObjectOutputStream oos2 = new ObjectOutputStream(new FileOutputStream(
                PRIVATE_KEY_FILE));
        oos1.writeObject(publicKey);
        oos2.writeObject(privateKey);
        /** 清空緩存,關閉文件輸出流 */
        oos1.close();
        oos2.close();
    }

    /**
     * 加密方法 source: 源數據
     */
    public static byte[] encrypt(String source) throws Exception {

        /** 將文件中的公鑰對象讀出 */
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
                PUBLIC_KEY_FILE));
        Key key = (Key) ois.readObject();
        ois.close();
        /** 得到Cipher對象來實現對源數據的RSA加密 */
        Cipher cipher = Cipher.getInstance(ALGORITHM_MODEL);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] b = source.getBytes();
        /** 執行加密操作 */
        byte[] b1 = cipher.doFinal(b);
        return b1;
    }

    /**
     * 解密算法 cryptograph:密文
     */
    public static String decrypt(byte[] cryptograph) throws Exception {
        /** 將文件中的私鑰對象讀出 */
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
                PRIVATE_KEY_FILE));
        Key key = (Key) ois.readObject();
        /** 得到Cipher對象對已用公鑰加密的數據進行RSA解密 */
        Cipher cipher = Cipher.getInstance(ALGORITHM_MODEL);
        cipher.init(Cipher.DECRYPT_MODE, key);
        /** 執行解密操作 */
        byte[] b = cipher.doFinal(cryptograph);
        return new String(b);
    }

    public static void main(String[] args) throws Exception {
        generateKeyPair();//生成密鑰對
        String source = "Hello World!";// 要加密的字符串
        byte[] cryptograph = encrypt(source);// 生成的密文

        //可以將密文進行base64編碼進行傳輸
        System.out.println(new String(Base64.encode(cryptograph)));

        String target = decrypt(cryptograph);// 解密密文
        System.out.println(target);
    }
}

RSA密鑰使用Base64編碼

要靈活使用肯定不能使用java的序列化保存了,我們對上面的generateKeyPair()方法進行改寫。通過密鑰生成器生成公鑰,私鑰后,調用publicKey.getEncoded()和privateKey.getEncoded(),此時它生成的比特編碼是有獨特格式的(公鑰是X.509,私鑰是PKCS#8)可以使用publicKey.getFormat(),privateKey.getFormat();進行查看。之后對字節碼進行Base64編碼就行了。

密鑰生成方法

    //以base64編碼密鑰
    public Map<String ,String> generateKeyPair1() throws Exception{
        SecureRandom sr = new SecureRandom();
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(1024, sr);
        KeyPair kp = kpg.generateKeyPair();
        Key publicKey = kp.getPublic();
        Key privateKey = kp.getPrivate();
        byte[] pb = publicKey.getEncoded();
        String pbStr =  new String(Base64.encode(pb));
        byte[] pr = privateKey.getEncoded();
        String prStr =  new String(Base64.encode(pr));
        Map<String, String> map = new HashMap<String, String>();
        map.put("publicKey",pbStr);
        map.put("privateKey", prStr);
        return map;
    }

恢復密鑰方法,使用各自不同的編碼形式恢復

    //從base64編碼的公鑰恢復公鑰
    public PublicKey getPulbickey(String key_base64) throws Exception{
        byte[] pb = Base64.decode(key_base64).getBytes();
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pb);
        KeyFactory  keyfactory = KeyFactory.getInstance("RSA");
        return keyfactory.generatePublic(keySpec);
    }
    //從base64編碼的私鑰恢復私鑰
    public PrivateKey getPrivatekey(String key_base64) throws Exception{
        byte[] pb = Base64.decode(key_base64).getBytes();
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pb);
        KeyFactory  keyfactory = KeyFactory.getInstance("RSA");
        return keyfactory.generatePrivate(keySpec);
    }

加密解密方法都類似下面,PrivateKey和PublicKey是Key的子接口。

    /** 執行加密操作 */
    public static byte[] encrypt(Key key,byte[] source) throws Exception{
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] ciphertext = cipher.doFinal(source);
        return ciphertext;
    }
    /** 執行加密操作 */
    public static byte[] decrypt(Key key,byte[] ciphertext) throws Exception{
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] source = cipher.doFinal(ciphertext);
        return source;
    }

記錄RSA的密鑰特征值并進行密碼恢復

所謂特征值就是RSA中公鑰(N,e)私鑰(N,d)的三個值:N,e,d。只要有這三個值我們就可以恢復密鑰了。這是實際開發中常用的方法。首先是提取特征值,我們需要將PublicKey強制轉換為RSAPublicKey.然后獲取,看代碼。

    //提取特征值保存,以base64編碼密鑰
        public static Map<String ,String> generateKeyPair2() throws Exception{
            SecureRandom sr = new SecureRandom();
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            kpg.initialize(1024, sr);
            KeyPair kp = kpg.generateKeyPair();
            Key publicKey = kp.getPublic();
            Key privateKey = kp.getPrivate();
            RSAPublicKey rpk = (RSAPublicKey)publicKey;
            RSAPrivateKey rpr= (RSAPrivateKey)privateKey;
            //三個特征值都是BigInteger類型。
            BigInteger N = rpk.getModulus();//N值
            BigInteger e = rpk.getPublicExponent();//e值
            BigInteger d  = rpr.getPrivateExponent();//d值
            Map<String, String> map = new HashMap<String, String>();
            //將BigInteger轉為byte[],然后以base64保存
            map.put("N",new String(Base64.decode(N.toByteArray())));
            map.put("e", new String(Base64.decode(e.toByteArray())));
            map.put("d", new String(Base64.decode(d.toByteArray())));
            return map;
        }

利用三個特征值就可以非常容易恢復密鑰了。

    //從base64編碼的特征值(N,e)恢復公鑰
        public static PublicKey getPulbickey(String N_Str,String e_Str) throws Exception{
            BigInteger N = new BigInteger(1, Base64.decode(N_Str.getBytes()));
            BigInteger e = new BigInteger(1, Base64.decode(e_Str.getBytes()));
            KeyFactory kf = KeyFactory.getInstance("RSA");
            RSAPublicKeySpec ps = new RSAPublicKeySpec(N, e);
            PublicKey pkey = kf.generatePublic(ps);
            return pkey;
        }
    //從base64編碼的特征值(N,d)恢復私鑰
    public static PrivateKey getPrivatekey(String N_Str,String d_Str) throws Exception{
        BigInteger N = new BigInteger(1, Base64.decode(N_Str.getBytes()));
        BigInteger d = new BigInteger(1, Base64.decode(d_Str.getBytes()));
        KeyFactory kf = KeyFactory.getInstance("RSA");
        RSAPrivateKeySpec ps = new RSAPrivateKeySpec(N, d);
        PrivateKey pkey = kf.generatePrivate(ps);
        return pkey;
    }

C#生成的密鑰java中使用–記錄特征值的例子

C#生成的公鑰是保存在xml文件中的,使用的是Base64編碼,因此我們先解析出密鑰對象,然后再使用公鑰加密,而讓C#端服務器進行解密。Modulus就是N值,Exponent就是e值,然后組成(N,e)公鑰。
C#的密鑰形式如:

<RSAKeyValue>
<Modulus>7gFGAUTUBiSi8j+oZ4JY4NUNCfdGIxFLhKE0c4SbiHvNAiD7rxWnmuqXK4nVzOyjJsmCViA1aRN3+Tf5xMqxtjjCKWNRWAp5LMp2AfL3DrDcWV/ZjwPIUO52yEa+q2PyJ0OMgRxBA80WWBzv+EJm7/rq8wP9gpVI+HY0ACH8Kmk=
</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
//從xml中獲取公鑰
    public static PublicKey getPublicKey(String xmlkey) throws Exception {
        Document doc = XmlUtil.parseXml(xmlkey);
        Node node = doc.getChildNodes().item(0);
        NodeList list = node.getChildNodes();
        String e = null, m = null;
        for (int i = 0; i < list.getLength(); i++) {
            String nodename = list.item(i).getNodeName();
            String value = list.item(i).getTextContent();
            if (nodename.equals("Modulus")) {
                e = value;
            } else if (nodename.equals("Exponent")) {
                m = value;
            }
        }
        BigInteger b1 = new BigInteger(1, Base64.decode(e.getBytes()));
        BigInteger b2 = new BigInteger(1, Base64.decode(m.getBytes()));
        System.out.println(b1 + "\n" + b2);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        RSAPublicKeySpec ps = new RSAPublicKeySpec(b1, b2);
        PublicKey pkey = kf.generatePublic(ps);
        return pkey;
    }

    //RSA加密
    public static byte[] encrypt(byte[] data,PublicKey publickey) {
        if (publickey == null || data == null) {
            return null;
        }
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, publickey);
            return cipher.doFinal(data);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    //字符串轉Document
    public static Document parseXml(String str) throws ParserConfigurationException, SAXException, IOException{
        StringReader reader = new StringReader(str);
        InputSource source = new InputSource(reader);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(source);
    }

4.編碼的使用

常見的編碼有Base64,HEX和對URL的編碼。這都是為了實際需要才進行的編碼。HEX是編碼成16進制字符,MD5一般就是以HEX進行編碼,這不說了。

Base64

Base64一開始是為了解決郵件中不能傳文件和圖片問題而使用的,將無法閱讀的二進制碼轉化成字符形式,字符為(A-Za-z0-9+/)。它的原理是將3個8位字節(24位)轉化為4個6位字節(24位),之后在6位的前面補兩個0,形成8位一個字節形式,如果剩下的不足3字節,則用0填充,輸出字符使用”=”,所以編碼后文本可能出現1個或2個’=’.這樣就將原本3個字節變成了4個字節,那就是64種編碼了。當然,除了對二進制數據編碼,還可以對字符串編碼來隱藏明文,讓別人不那么容易看懂。
由于jdk中的base64是不開發使用了 ,所有需要下載到網上下載Base64包,我使用的是 javaBase64-1.2.jar,另外android sdk中是帶有base64的,位置是android.util.Base64

/*這里使用的是android.util.base64*/
byte[] input = "hello world".getBytes("utf8");
//編碼    
byte[] encodeData = Base64.encode(input , 0);
//解碼        
byte[] result = Base64.decode(encodeData , 0);

URL的編碼

url一般使用的都是英文、數字和某些符號,而對于特殊符號,中文等這些是不允許使用的。因此我們要在url請求中加入特殊符號,中文等就需要對它們進行編碼。http請求時,url部分是必須編碼的,get的請求字段可以不進行url編碼。比如
http://www.baidu.com/中文?wd=國際
“中文”必須進行url編碼,“國際”可以不用。
那url編碼到底是怎么進行編碼的呢?
都是在16進制前面加上‘%’表示。對于一些字符使用的是”%xx”,而對于中文,就是多個”%xx%xx%xx”,xx的數字有編碼的16進制決定(沒有指定字符編碼(utf8),則使用默認編碼),然后每一字節前面加”%”。
Android 中提供的URL編碼解碼方法。

String d = URLEncoder.encode('中文',"utf8");
String f = URLDecoder.decode("%20");

RSA參考文章:
【1】 RSA算法使用介紹
【2】使用X.509數字證書加密解密實務(二)– 證書的獲得和管理

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內容