閱讀200 返回首頁    go 小米 go 小米6


Java aes加密C#解密的取巧方法

項目開發過程中遇到一個棘手的問題:A係統使用java開發,通過AES加密數據,B係統使用C#開發,需要從A係統獲取數據,但在AES解密的時候遇到麻煩。Java的代碼和C#的代碼無法互通。


Java代碼:

/** 
	 * 加密 
	 *  
	 * @param content 需要加密的內容 
	 * @param password  加密密鑰
	 * @return 
	 */  
	public static String encrypt(String content, String password) {  
        try {            
            //如下代碼用於根據原始的password生成加密的key,這段代碼C#是沒有對應的實現的
            KeyGenerator kgen = KeyGenerator.getInstance("AES"); 
            java.security.SecureRandom random = java.security.SecureRandom.getInstance("SHA1PRNG");
            random.setSeed(password.getBytes()); 
            kgen.init(128, random);  
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();

            //如下代碼是標準的AES加密處理,C#可以實現
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");		  
            byte[] byteContent = content.getBytes("utf-8");  
            cipher.init(Cipher.ENCRYPT_MODE, key);			
            return Codec.encodeBASE64(cipher.doFinal(byteContent));
        } catch (Exception e) {  
            Logger.error(e,"AES加密異常");
        }  
        return null;
	} 

網上找了一些資料,沒有找到滿意的解決方案,於是嚐試了一種取巧的方法,具體實現如下:

1)將Java中key的處理代碼抽取出來,寫成一個簡單的工具類,類名為TestGenAESByteKey。

      TestGenAESByteKey將原始的password轉換為AES加密需要的字節,然後Base64編碼,得到字符串

2)將以上步驟得到的字符串通過人工的方式拷貝到C#的代碼中,作為秘鑰解密


具體代碼如下:

TestGenAESByteKey(Java語言)

package api;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

import sun.misc.BASE64Encoder;

public class TestGenAESByteKey{

	/**
	 * @param args
	 * @throws UnsupportedEncodingException 
	 * @throws NoSuchAlgorithmException 
	 */
	public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException {
	    KeyGenerator kgen = KeyGenerator.getInstance("AES"); 
        java.security.SecureRandom random = java.security.SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(args[0].getBytes()); 
        kgen.init(128, random);  
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        BASE64Encoder coder = new BASE64Encoder();
        
        System.out.println(coder.encode(enCodeFormat));
	}

}

C#的解密代碼:

public static string decrypt(string toDecrypt,string key)
       {
           byte[] keyArray = Convert.FromBase64String(key); //將TestGenAESByteKey類輸出的字符串轉為byte數組
           byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);
           RijndaelManaged rDel = new RijndaelManaged();
           rDel.Key = keyArray;
           rDel.Mode = CipherMode.ECB;        //必須設置為ECB
           rDel.Padding = PaddingMode.PKCS7;  //必須設置為PKCS7
           ICryptoTransform cTransform = rDel.CreateDecryptor();
           byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
           return UTF8Encoding.UTF8.GetString(resultArray);
       }


例如:原始密碼為123456,經過TestGenAESByteKey處理後,輸出a7SDfrdDKRBe5FaN2n3Gfg==

將a7SDfrdDKRBe5FaN2n3Gfg==作為C#函數decrypt的key參數的值傳進去,就可以正常解碼了


需要注意幾點:

1)C#默認運算模式為CBC,java默認為ECB,因此要將C#的加密方式改為ECB

2)C#的Padding方式要設置為PaddingMode.PKCS7,否則解密出來後結尾可能有亂碼




最後更新:2017-04-03 12:53:42

  上一篇:go C++編程規範之7:編程中應該知道何時和如何考慮可伸縮性
  下一篇:go android抓屏