摘要: 项目开发过程中遇到一个棘手的问题:A系统使用java开发,通过AES加密数据,B系统使用C#开发,需要从A系统获取数据,但在AES解密的时候遇到麻烦。Java的代码和C#的代码无法互通。 Java代码: /** * 加密 * * @param content 需要加密的内...
项目开发过程中遇到一个棘手的问题: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; //必须设置为ECBrDel.Padding = PaddingMode.PKCS7; //必须设置为PKCS7ICryptoTransform 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,否则解密出来后结尾可能有乱码