Java端和JS端的AES加密解密同步

Java端和JS端的AES加密算法同步
公司要求登錄時用戶名和密碼必須先加密,再將數據發送到服務器。由於這種加密必須要求是可逆的,所以不能用MD5來加密,MD5不是可逆的。後臺選擇了用AES加密。然後問題就是如何跟公司的Java算法得到同樣的結果。
後來在搜尋了很多算法後,發現瞭解決方案,改動公司的算法,然後就可以輕鬆匹配了。
• Java端的算法:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
public class Encryption
{
    public static void main(String args[]) throws Exception {
        System.out.println("encrypted: "+encrypt());
        System.out.println("decrypted: "+desEncrypt().trim());
    }
public static String encrypt() throws Exception {
        try {
            String data = "123456";
            String key = "1234567812345678";
            String iv = "1234567812345678";
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            int blockSize = cipher.getBlockSize();
byte[] dataBytes = data.getBytes();
            int plaintextLength = dataBytes.length;
            if (plaintextLength % blockSize != 0) {
                plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
            }
byte[] plaintext = new byte[plaintextLength];
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
            byte[] encrypted = cipher.doFinal(plaintext);
return new sun.misc.BASE64Encoder().encode(encrypted);
} catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
public static String desEncrypt() throws Exception {
        String encrypted = encrypt() ;
        try
        {
            String data = encrypted ;
            String key = "1234567812345678";
            String iv = "1234567812345678";
byte[] encrypted1 = new BASE64Decoder().decodeBuffer(data);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original);
            return originalString;
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

算法得到的結果爲:

encrypted: aK7+UX24ttBgfTnAndz9aQ==
decrypted: 123456

• React native 裏的處理
需要的庫爲 crypto-js

import CryptoJS from 'crypto-js';

代碼如下:

encryptFun() {
    var data = "123456";
    var key  = CryptoJS.enc.Latin1.parse('1234567812345678');
    var iv   = CryptoJS.enc.Latin1.parse('1234567812345678');  
    //加密
    var encrypted = CryptoJS.AES.encrypt(
      data,
      key,
      {iv:iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.ZeroPadding
    });
    console.log('encrypted: ' + encrypted) ;
    //解密
    var decrypted = CryptoJS.AES.decrypt(encrypted,key,{iv:iv,padding:CryptoJS.pad.ZeroPadding});
    console.log('decrypted: '+decrypted.toString(CryptoJS.enc.Utf8));
  }

得到的結果跟java裏相同。這樣就同步種語言的加密了。
期間參考了很多資料,比如SO上一篇:
http://stackoverflow.com/questions/22607791/aes-encryption-using-java-and-decryption-using-javascript
裏面寫到

Your Java code uses the 128-bit AES key while your JavaScript code
uses the 256-bit AES key. Your Java code uses the
“Abcdefghijklmnop”.getBytes() as the actual key value, while your
JavaScript code uses the “Abcdefghijklmnop” as the passphrase from
which the actual key is derived. The default transformation for Java
AES is AES/ECB/PKCS5Padding, while default transformation for CryptoJS
is AES/CBC/PKCS7Padding.

這個讓我知道一些默認的格式轉換問題。不過徹底解決問題的還是下面的這個網站:
AES加密CBC模式兼容互通四種編程語言平臺【PHP、Javascript、Java、C#】
http://my.oschina.net/Jacker/blog/86383
肯定有更多的解決方案,只是我還沒懂。還得多學習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章