C#对称加密算法Java实现

最近因为业务需求,需要把一段C#编写的加密代码采用Java进行实现,在此记下我的实施过程和过程中碰到的一些问题以备后用。为了便于观察,只贴上C#源码中关键的部分:
 1 ///
 2 ///<summary>
 3 /// 加密方法
 4 /// </summary>
 5 /// <param name=\"Source\">待加密的串</param>
 6 /// <returns>经过加密的串</returns>
 7 public static string Encrypto(string Source)
 8 {
 9     byte[] bytIn = UTF8Encoding.UTF8.GetBytes(Source);
10     MemoryStream ms = new MemoryStream();
11     mobjCryptoService.Key = GetLegalKey();
12     mobjCryptoService.IV = GetLegalIV();
13     //创建对称加密器对象
14     //下面的控制台打印是我自己添加方便观察的
15     Console.WriteLine("KeySize:" + mobjCryptoService.KeySize);
16     Console.WriteLine("LegalKeySizes:" + mobjCryptoService.LegalKeySizes.Length);
17     Console.WriteLine("Mode:"+ mobjCryptoService.Mode);
18     Console.WriteLine("Padding:"+mobjCryptoService.Padding);
19     ICryptoTransform encrypto = mobjCryptoService.CreateEncryptor();
20     //定义将数据流链接到加密转换的流
21     CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write);
22     cs.Write(bytIn, 0, bytIn.Length);
23     cs.FlushFinalBlock();
24     ms.Close();
25     byte[] bytOut = ms.ToArray();
26 
27     return Convert.ToBase64String(bytOut);
28 }
29 
30 ///
31 ///<summary>
32 /// 解密方法
33 /// </summary>
34 /// <param name=\"Source\">待解密的串</param>
35 /// <returns>经过解密的串</returns>
36 public static string Decrypto(string Source)
37 {
38     try
39     {
40         byte[] bytIn = Convert.FromBase64String(Source);
41         MemoryStream ms = new MemoryStream(bytIn, 0, bytIn.Length);
42         mobjCryptoService.Key = GetLegalKey();
43         mobjCryptoService.IV = GetLegalIV();
44         //创建对称解密器对象
45         ICryptoTransform encrypto = mobjCryptoService.CreateDecryptor();
46         //定义将数据流链接到加密转换的流
47         CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read);
48         StreamReader sr = new StreamReader(cs);
49         return sr.ReadToEnd();
50     }
51     catch (Exception)
52     {
53         return string.Empty;
54     }
55 }

其中有一个问题:
1 //生成加密器的对象由RijndaelManaged得来,那么这个RijndaelManaged对象是干嘛的?第三方的?原生的?
2 private static SymmetricAlgorithm mobjCryptoService = new RijndaelManaged();

调查之后,好吧,它是一种对称加密算法(可以理解为在双方之间可以实现加解密),以下来自百科:
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。
之前对加密标准认识的并不多,但是通过代码来看,似乎实现对称加密还需要别的材料,看到下面这两个方法
 1 /// <summary>
 2 /// 获得密钥
 3 /// </summary>
 4 /// <returns>密钥</returns>
 5 private static byte[] GetLegalKey()
 6 {
 7     string _TempKey = Key;//Key已经预先写死在代码里了
 8     mobjCryptoService.GenerateKey();
 9     byte[] bytTemp = mobjCryptoService.Key;
10     int KeyLength = bytTemp.Length;
11     if (_TempKey.Length > KeyLength)
12         _TempKey = _TempKey.Substring(0, KeyLength);
13     else if (_TempKey.Length < KeyLength)
14         _TempKey = _TempKey.PadRight(KeyLength, ' ');
15       return ASCIIEncoding.ASCII.GetBytes(_TempKey);
16 }
17 //GetLegalKey方法每次都会返回一个长度为32的byte数组
18 //mobjCryptoService.Key = GetLegalKey();
19 
20 /// <summary>
21 /// 获得初始向量IV
22 /// </summary>
23 /// <returns>初试向量IV</returns>
24 private static byte[] GetLegalIV()
25 {
26     string _TempIV = "$%^&*()_osudghwe7%%2kdijskldglk2397^&*wigwuqwelkn";//这是虚构的
27     mobjCryptoService.GenerateIV();
28     byte[] bytTemp = mobjCryptoService.IV;
29     int IVLength = bytTemp.Length;
30     if (_TempIV.Length > IVLength)
31         _TempIV = _TempIV.Substring(0, IVLength);
32     else if (_TempIV.Length < IVLength)
33         _TempIV = _TempIV.PadRight(IVLength, ' ');
34     return ASCIIEncoding.ASCII.GetBytes(_TempIV);
35 }
36 //GetLegalIV方法每次都会返回一个长度为16的byte数组
37 //mobjCryptoService.IV = GetLegalIV();

虽然是通过两个方法来取得的KEY和IV(二者都是byte数组),但是KEY和IV都是预先写死在代码里的,只不过是返回了特定长度的byte数组。
1 //RijndaelManaged,这是对称算法合法的key和IV的长度(分别以位来计算)
2 //        Legal min key size = 128
3 //        Legal max key size = 256
4 //        Legal min block size = 128
5 //        Legal max block size = 256

经过调查,还需要配置算法的mode和padding,此处并没有进行设置,所以默认分别为CipherMode.CBC和PaddingMode.PKCS7。详见modepadding

目前来看,需要调查的可以告一段落了,那么接下来,就需要调查如何Java实现了。在Java中,实现加密需要用到JCE提供的Cipher对象,类比C#的实现,借鉴广大程序员的智慧,我首先尝试写了一下(只贴出关键部分)
 1 public void init(byte[] keyBytes) {
 2 
 3     // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要
 4     int base = 16;
 5     if (keyBytes.length % base != 0) {
 6         int groups = keyBytes.length / base
 7                 + (keyBytes.length % base != 0 ? 1 : 0);
 8         byte[] temp = new byte[groups * base];
 9         Arrays.fill(temp, (byte) 0);
10         System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
11         keyBytes = temp;
12     }
13     // 转化成JAVA的密钥格式
14     key = new SecretKeySpec(keyBytes, "AES");
15     try {
16         // 初始化cipher
17         cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
18     } catch (NoSuchAlgorithmException e) {
19         e.printStackTrace();
20     } catch (NoSuchPaddingException e) {
21         e.printStackTrace();
22     } 
23 }
24 
25 /**
26  * 加密方法
27  * @param content 待加密內容字符串
28  * @param keySrc 加解密密秘钥字符串
29  * @param iv 算法所需向量
30  * @return
31  * @throws UnsupportedEncodingException
32  */
33 public String encrypt(String content, String keySrc,String iv) throws UnsupportedEncodingException {
34     byte[] encryptedText = null;
35     init(keySrc.getBytes("utf-8"));
36     try {
37         cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv.getBytes()));
38         encryptedText = cipher.doFinal(content.getBytes("utf-8"));
39     } catch (Exception e) {
40         e.printStackTrace();
41     }
42     return Base64.encodeBase64String(encryptedText);
43 }
44 
45 /**
46  * 解密方法
47  * @param encryptedData 待解密数据
48  * @param keySrc 加解密密秘钥字符串
49  * @param iv 算法所需向量
50  * @return
51  * @throws UnsupportedEncodingException 
52  */
53 public String decrypt(String encryptedData, String keySrc,String iv) throws UnsupportedEncodingException {
54     byte[] decryptedText = null;
55     init(keySrc.getBytes("utf-8"));
56     try {
57         cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv.getBytes()));
58         decryptedText = cipher.doFinal(Base64.decodeBase64(encryptedData));
59     } catch (Exception e) {
60         e.printStackTrace();
61     }
62     return new String(decryptedText);
63 }
64 
65 public static void main(String[] args) throws UnsupportedEncodingException {
66     EncryptingUtil eu = new EncryptingUtil();
67     
68     String content = "abc";
69     // 加密字符串
70     System.out.println("加密前的:" + content);
71     // 加密方法
72     String enc = eu.encrypt(content,"秘钥值","向量值");
73     System.out.println(enc);
74     // 解密方法
75     String dec = eu.decrypt(enc,"秘钥值", "向量值");
76     System.out.println("解密后的内容:" + dec);
77 }

Java版本的实现,目前有几个问题,一个就是补齐方式的问题,在C#中默认的补齐方式PKCS7,但是Java默认并不支持该补齐方式,只有PKCS5;其次就是秘钥的长度问题,C#代码中的秘钥长度是256位的,但是Java默认最大支持128位的,执行时会报出”Illegal key size”的问题。这位大牛的东东帮到我了,感谢。查看

当需要使用256位长度的秘钥时,需要下载对应Java版本的JCE拓展包,图中的问题就是因为JCE拓展包和Java版本不匹配引起的

posted on 2016-03-28 22:12 都较瘦 阅读(196) 评论(0)  编辑  收藏 所属分类: 工具案例积累Java相关案例积累


只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问  
 
<2016年3月>
282912345
6789101112
13141516171819
20212223242526
272829303112
3456789

导航

统计

公告

博客定位:囿于目前的水平,博客定位在记录自己的学习心得和随手的练习

常用链接

留言簿

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜