关于Windows Phone 中加密算法使用.最近一段时间很多做Windows Phone应用同学在微博上提了不少问题.其实在客户端实际需求中大多都会涉及到数据基于加密算法的解析和加密.本篇幅针对Windows Phone数据加密算法的问题.给出一些解决方案.
首先有必要来说说为何会存在Windows Phone数据加密的问题.做过Silverlight的同学应该知道.在Silverlight 4版本 .NET类库中基于System.Security.Cryptography命名空间下.保留了Aes加密算法.关于数据DES和TripleDES[3DES]加密算法已经不存在了.同样在Windows Phone SDK 7.1.1最新版本中.也能够看出除了SHA1和HMAC_SHA1对称算法外.如果我们尝试做MD5或对称的HMAC_MD5加密操作发现官方的SDK并没有提供类似支持的类. 如是问题就这么出现了.
如果需要在服务器端和和客户端传递类似MD5、HMAC_MD5或是解析服务器端传递的DES、TripleDES[3DES]数据是发现现在Windows Phone针对数据加密和解析并没有对应的支持.其实这些问题.原来都在我们团队实际Coding过程都碰到过.也算是找到一些比较成熟的解决方案.如下.
本篇幅针对MD5,HMAC_MD5,DES,TripleDES[3DES]算法给出Windows Phone移植版本.
首先来说说MD5.
MD5[Message Digest Algorithm MD5]用于确保信息传输完整一致,在计算机广泛使用的杂凑算法之一[又译摘要算法、哈希算法].比较常见使用于保证数据完整性.MD5或者说HASH值是一种不可逆的算法.在.NET 4中也提供类似在System.Security.Cryptography.MD5命名空间下MD5CryptoServiceProvider 类的对应实现.针对Silverlight和WP对应版本不支持MD5的情况,微软官方在archive.msdn上给出对应的MD5 Silverlight移植版本.[同样使用于Windows Phone]:
Silverlight MD5 Implementation:
[http://archive.msdn.microsoft.com/SilverlightMD5]
具体实现Code也可以参考GitHub上地址.这里不再赘述.
HMAC_MD5.
使用 MD5 哈希函数计算基于哈希值的消息验证代码 [HMAC].
HMACMD5 是从 MD5 哈希函数构造的一种键控哈希算法,被用作基于哈希的消息验证代码 [HMAC].此 HMAC 进程将密钥与消息数据混合,使用哈希函数对混合结果进行哈希计算,将所得哈希值与该密钥混合,然后再次应用哈希函数。输出的哈希值长度为 128 位.
关于HMAC_MD5算法除了在Codeplex 上[http://hmacmd5.codeplex.com/] 找到HMACmd5 Codeplex已经在Windows Phone验证通过外:
HMACMD5 For Silverlight/Windows Phone:
http://hmacmd5.codeplex.com/
其他第三方方式均没有验证过.考虑该算法核心并不复杂.于是自己动手重写一个基于Windows Phone 版本HMACMD5的实现[验证通过]. 核心类如下:
1: ?
using System;
2:
using System.Net;
3:
using System.Windows;
4:
using System.Windows.Controls;
5:
using System.Windows.Documents;
6:
using System.Windows.Ink;
7:
using System.Windows.Input;
8:
using System.Windows.Media;
9:
using System.Windows.Media.Animation;
10:
using System.Windows.Shapes;
11:
12:
namespace DataEncryptBuildDemo.DataEncryptCommon
13: {
14:
/// <summary>
15:
/// HMACMD Data Encrypt Operator
16:
/// Author:chenkai Data:6/7/2011
17:
/// </summary>
18:
public
class HMACMD5DataEncrypt
19: {
20:
/// <summary>
21:
/// HMAC_MD5 DataEncrypt
22:
/// </summary>
23:
/// <param name="original">明文</param>
24:
/// <param name="key">密钥</param>
25:
/// <returns>返回加密的字符串</returns>
26:
public
static
string HMAC_MD5(
string original,
string key)
27: {
28:
byte[] b_tmp;
29:
byte[] b_tmp1;
30:
if (key ==
null)
31: {
32:
return
null;
33: }
34:
byte[] digest =
new
byte[512];
35:
byte[] k_ipad =
new
byte[64];
36:
byte[] k_opad =
new
byte[64];
37:
38:
byte[] source = System.Text.UTF8Encoding.UTF8.GetBytes(key);
39:
//System.Security.Cryptography.MD5 shainner = new MD5CryptoServiceProvider();
40:
41:
for (
int i = 0; i < 64; i++)
42: {
43: k_ipad[i] = 0 ^ 0x36;
44: k_opad[i] = 0 ^ 0x5c;
45: }
46:
47:
try
48: {
49:
if (source.Length > 64)
50: {
51:
//shainner = new MD5CryptoServiceProvider();
52: source = MD5Core.GetHash(source);
//shainner.ComputeHash(source);
53: }
54:
55:
for (
int i = 0; i < source.Length; i++)
56: {
57: k_ipad[i] = (
byte)(source[i] ^ 0x36);
58: k_opad[i] = (
byte)(source[i] ^ 0x5c);
59: }
60:
61: b_tmp1 = System.Text.UTF8Encoding.UTF8.GetBytes(original);
//内容
62: b_tmp = Adding(k_ipad, b_tmp1);
63:
64:
65:
//shainner = new MD5CryptoServiceProvider();
66: digest = MD5Core.GetHash(b_tmp);
//shainner.ComputeHash(b_tmp);
67: b_tmp = Adding(k_opad, digest);
68:
69:
70:
//shainner = new MD5CryptoServiceProvider();
71: digest = MD5Core.GetHash(b_tmp);
//shainner.ComputeHash(b_tmp);
72:
return ByteToString(digest);
73: }
74:
catch (Exception e)
75: {
76:
throw e;
77: }
78: }
79:
80:
/// <summary>
81:
/// 填充byte
82:
/// </summary>
83:
/// <param name="a"></param>
84:
/// <param name="b"></param>
85:
/// <returns></returns>
86:
private
static
byte[] Adding(
byte[] a,
byte[] b)
87: {
88:
byte[] c =
new
byte[a.Length + b.Length];
89: a.CopyTo(c, 0);
90: b.CopyTo(c, a.Length);
91:
return c;
92: }
93:
94:
/// <summary>
95:
/// Byte To String
96:
/// </summary>
97:
/// <param name="buff"></param>
98:
/// <returns></returns>
99:
private
static
string ByteToString(
byte[] buff)
100: {
101:
string sbinary =
"";
102:
103:
for (
int i = 0; i < buff.Length; i++)
104: {
105: sbinary += buff[i].ToString(
"X2");
// hex format
106: }
107:
return (sbinary);
108: }
109: }
110: }
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
具体代码也可以从HMACMD5 For Windows Phone GitHub上可以查看.如上代码验证通过.
TripleDES[3DES]
Triple DES又称3DES,是DES加密算法的一种模式.[TDEA,Triple Data Encryption Algorithm]块密码的通称。它相当于是对每个数据块应用三次DES加密算法.现在计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法.
一开始我大概看了DES 算法在C下面的实现很简单.费了点时间很快就移植Windows Phone DES算法版本. DES算法的核心采用位运算的. 每次8个字节也就是64位内容.密钥key也为64位.然后经过16轮置换. 可惜 TripleDES[3DES]始终没有移植成功.重复造轮子无果后.果断寻求第三方解决方案.
在Silverlight和Windows Phone 在CodePlex值得推荐开源第三方库是SSH.NET Library
SSH.NET Library:
http://sshnet.codeplex.com/
SSH.NET Library库移植灵感是来源于Java版本.不过SSH。NET是完全基于.NET 没有采用任何第三方组件和引用. 其中实现也包含同步和异步的封装. Socket通信库. HTTP代等.其中最为重要的是基于.NET 实现DES和TripleDES[3DES] 两种核心算法. 并且支持.NET 3.5 、Silverlight、Windows Phone.
当然除了Codeplex上这个比较成熟SSH.NET Library开源组件外.关于DES和TripleDES[3DES] 还可以找到其他类似可选的开源组件.针对Windows Phone 缺乏3DES支持.国外一个WP 开发者Nicolas Humann[Link in] 基于broccoliproducts 的DES, TripleDES and BlowFish in Silverlight 版本库做了进一步的集成和封装. 并成功移植DES和TripleDES[3DES]Windows phone版本:
Nicolas Humann[Link in] DES And TripleDES[3DES] Component:
TripleDES Cryptography On Silverlight And Windows Phone
针对Nicolas Humann[Link in] 这个3DES版本移植ku.在其基础做了进一步的封装.为了是实现对TripleDESCryptoServiceProvider 类[3DES核心实现类]对数据加密和解密的操作. 大概分为两种情况.一种是需要IV密钥Key 另外一种不需要密钥Key 数据基于3DES和DES 加密和解密的封装. 核心Code如下:
1:
using System;
2:
using System.Net;
3:
using System.Windows;
4:
using System.Windows.Controls;
5:
using System.Windows.Documents;
6:
using System.Windows.Ink;
7:
using System.Windows.Input;
8:
using System.Windows.Media;
9:
using System.Windows.Media.Animation;
10:
using System.Windows.Shapes;
11:
12:
using System.Text;
13:
using System.Security.Cryptography;
14:
using DataEncryptBuildDemo.DataEncryptCommon.DESDataEncrypt;
15:
16:
namespace DataEncryptBuildDemo.DataEncryptCommon
17: {
18:
/// <summary>
19:
/// Des And TripleDES DataEncrypt Operator
20:
/// Author:chenkai Date:14/5 2012
21:
/// </summary>
22:
public
class Des_DataEncrypt
23: {
24:
/// <summary>
25:
/// TripleDes Data Encrypt With Ot Encrypt Key Operator
26:
/// </summary>
27:
/// <param name="sourceContent">Source Need to TripleDes Encrpt Data</param>
28:
/// <returns>Encrypt Data Byte[] String</returns>
29:
public
static
byte[] TripleDesEncryptWithOutKey(
string sourceContent)
30: {
31:
if (
string.IsNullOrEmpty(sourceContent))
32:
return
null;
33:
34: var toEncryptSourceStr = Encoding.UTF8.GetBytes(sourceContent);
35: TripleDESCryptoServiceProvider tripleDesEncryptProvider =
new TripleDESCryptoServiceProvider();
36: ICryptoTransform encryptTransform=tripleDesEncryptProvider.CreateEncryptor();
37:
byte[] encryptToBytes = encryptTransform.TransformFinalBlock(toEncryptSourceStr, 0, toEncryptSourceStr.Length);
38:
39:
return encryptToBytes;
40: }
41:
42:
/// <summary>
43:
/// TripleDes Data DeEncrypt With Out Encrypt Key Operator
44:
/// </summary>
45:
/// <param name="encryptBytes">Encrypt Byte Array</param>
46:
/// <returns>DeEncrypt SourceContent String</returns>
47:
public
static
string TripleDesDeEncryptWithOutKey(
byte[] encryptBytes)
48: {
49:
if (encryptBytes ==
null || encryptBytes.Length <= 0)
50:
return
string.Empty;
51:
52: TripleDESCryptoServiceProvider tripleDesProvider =
new TripleDESCryptoServiceProvider();
53: ICryptoTransform deEncryptTransform = tripleDesProvider.CreateDecryptor();
54: var deEncryptBytes = deEncryptTransform.TransformFinalBlock(encryptBytes, 0, encryptBytes.Length);
55: var deEncryptFormatStr = Encoding.UTF8.GetString(deEncryptBytes, 0, deEncryptBytes.Length);
56:
57:
return deEncryptFormatStr;
58: }
59:
60:
/// <summary>
61:
/// TripleDes Data Encrypt Use IVKey Operator
62:
/// </summary>
63:
/// <param name="sourceContent">Source Content</param>
64:
/// <param name="encryptKey">Encrypt Key</param>
65:
/// <returns>Encrypt Bytes Array</returns>
66:
public
static
byte[] TripleDesEncryptUseIvKey(
string sourceContent,
byte[] encryptIVKey)
67: {
68:
if (
string.IsNullOrEmpty(sourceContent) || encryptIVKey ==
null || encryptIVKey.Length <= 0)
69:
return
null;
70:
71: var toEncryptSourceStr = Encoding.UTF8.GetBytes(sourceContent);
72: TripleDESCryptoServiceProvider tripleDesProvider =
new TripleDESCryptoServiceProvider();
73:
74:
//No Seting Pading
76: var key = tripleDesProvider.Key;
//Save Key
77: IsolatedStorageCommon.IsolatedStorageSettingHelper.AddIsolateStorageObj(
"EncryptKey", key);
78: ICryptoTransform encryptTransform = tripleDesProvider.CreateEncryptor(key, encryptIVKey);
79: var encryptBytes = encryptTransform.TransformFinalBlock(toEncryptSourceStr, 0, toEncryptSourceStr.Length);
80:
81:
return encryptBytes;
82: }
83:
84:
85:
86:
/// <summary>
87:
/// Triple Des DeEncrypt Operator Use IvKey
88:
/// </summary>
89:
/// <param name="encryptKey">Encrypt key can be null</param>
90:
/// <param name="ivKey">Iv</param>
91:
/// <param name="encryptBytes">EncryptBytes</param>
92:
/// <returns>Return String </returns>
93:
public
static
string TripleDesDeEncryptUseIvKey(
byte[] encryptKey,
byte[] ivKey,
byte[] encryptBytes)
94: {
95:
if (encryptBytes ==
null || encryptBytes.Length <= 0)
96:
return
string.Empty;
97:
98: TripleDESCryptoServiceProvider tripleDesProvider =
new TripleDESCryptoServiceProvider();
99:
100:
if (encryptKey ==
null)
101: encryptKey = IsolatedStorageCommon.IsolatedStorageSettingHelper.GetIsolateStorageByObj(
"EncryptKey")
as
byte[];
102: ICryptoTransform deEncryptTransform = tripleDesProvider.CreateDecryptor(encryptKey, ivKey);
103: var DecryptBytes = deEncryptTransform.TransformFinalBlock(encryptBytes, 0, encryptBytes.Length);
104:
string unDecryptFomatStr = Encoding.UTF8.GetString(DecryptBytes, 0, DecryptBytes.Length);
105:
106:
return unDecryptFomatStr;
107: }
108: }
109: }
当然这个只是Nicolas Humann[Link in] 对3DEs Windows Phone版本进一步封装. 目的方便能够形成一套API.无需关心TripleDESCryptoServiceProvider 类具体如何实现.至于这段代码可以GitHub上找到.验证通过.
至此关于应用开发常见的MD5、MAC_MD5、DES、3DES Windows Phone移植版本算法可用库如上.如上代码均实际项目中验证通过.对于还在苦苦重复造轮子同学.如果觉得为了使用效率.还是值得参考的.
关于本片全部源码可以GitHub下载到[ https://github.com/chenkai/DataEncryptWindowsPhoneDemo ].如有Bug请即时反馈 Email:[email protected]
或通过Sina 微博:[http://weibo.com/chenkaihome] 即时沟通.
参考链接:
TripleDES Cryptography On Silverlight And Windows Phone
DES, TripleDES and BlowFish in Silverlight