在程序中加密解密是我们常要用到的功能,比如对密码,数据库连接字符串,PIN等的加密。虽然Windows Phone限制了应用程序仅能访问自己的独立存储,但是将重要数据以明文的形式存储在Isolated Storage依然是不安全的。在Windows Phone中加密解密通过Data Protection API (DPAPI)来实现。如果对加密解密有所了解的朋友会清楚,非对称的加密我们需要用到密钥对,而这往往需要我们自己生成,同时密钥本身需要存储,或者通过第三方机构颁布证书等的方式来验证信息的可靠性。而Windows Phone为我们简化了这个难题,每一个程序在第一次运行的时候就可以获得它自己的解密密钥。而我们只需要借助
ProtectedData
类的
Protect
和
Unprotect
方法分别实现加密和解密。对于数据类型的文件,直接可以对数据库加密,在连接字符串中使用Password参数即可。当然连接字符串本身也需要进行加密和解密,以防止密码泄露。
接下来我将演示如何在Windows Phone 应用程序中运用这两个方法。本文请参考MSDN文档
http://msdn.microsoft.com/zh-cn/library/hh487164(v=VS.92).aspx
创建项目
1. 创建Windows Phone 7项目EncryptionAndDecryptionWP
2. 添加TextBox控件txtData
3. 添加btnStore按钮,用于加密数据,将加密结果保存在内存中
4. 添加btnRetrieve按钮,用于解密数据,并将解密结果用弹出对话框显示。
ContentPanel
部分的
XAML
如下
:
<
Grid
x:Name
="LayoutRoot"
Background
="Transparent"
>
<
Grid
x:Name
="ContentPanel"
Grid.Row
="1"
Margin
="12,150,12,0"
>
<
StackPanel
Orientation
="Vertical"
>
<
TextBox
x:Name
="txtData"
Height
="80"
Width
="460"
Foreground
="
{StaticResource PhoneAccentBrush}
"
FontSize
="
{StaticResource PhoneFontSizeLarge}
"
/>
<
Button
x:Name
="btnStore"
Content
="Store"
Height
="71"
Width
="160"
BorderBrush
="
{StaticResource PhoneAccentBrush}
"
Foreground
="
{StaticResource PhoneAccentBrush}
"
Click
="btnStore_Click"
/>
<
Button
x:Name
="btnRetrieve"
Content
="Retrieve"
Height
="71"
Width
="160"
BorderBrush
="
{StaticResource PhoneAccentBrush}
"
Foreground
="
{StaticResource PhoneAccentBrush}
"
Click
="btnRetrieve_Click"
/>
</
StackPanel
>
</
Grid
>
</
Grid
>
加密数据
当单击btnStore后,加密txtData中的数据,并保存在变量中,代码如下:
private
byte[] _encryptedBytes;
private
void btnStore_Click(
object sender, RoutedEventArgs e)
{
var sourceBytes = Encoding.UTF8.GetBytes(txtData.Text.Trim());
_encryptedBytes = ProtectedData.Protect(sourceBytes,
null);
}
解密数据
当单击btnRetrieve后,解密数据,代码如下:
private
void btnRetrieve_Click(
object sender, RoutedEventArgs e)
{
if (_encryptedBytes ==
null)
return;
var bytes = ProtectedData.Unprotect(_encryptedBytes,
null);
if (bytes !=
null) MessageBox.Show(Encoding.UTF8.GetString(bytes,
0, bytes.Length));
}
运行结果:输入admin
其它说明:通常情况下,我们需要将加密后的数据保存在独立存储中;Protect与Unprotect的第二个参数是信息熵,可以增加加密的复杂度,可以均为null,同时必须保持一致。
关于WP7平台的安全策略,可以参考MSDN:Windows Phone 安全性
其支持的加密算法包括:AES、HMACSHA1、HMACSHA256、Rfc2898DeriveBytes、RSA、SHA1、SHA256。
还可以参考codeplex上的开源项目:Scrypt RSA Cryptography for Silverlight 3+ and Windows Phone 7
另:.NET Framework中的AES加密通过AesManaged类来操作的,下面的程序使用此类和Rfc2898DeriveBytes类对资料进行加密
代码如下:
//
注意AES是一个对称加密算法,用来加密和解密数据的密码和salt值必须相同
public
class AESEncryption
{
///
<summary>
///
加密数据
///
</summary>
///
<param name="dataToEncrypt">
要加密的字符串
</param>
///
<param name="password">
密码
</param>
///
<param name="salt">
salt值
</param>
///
<returns></returns>
public
static
string Encrypt(
string dataToEncrypt,
string password,
string salt)
{
AesManaged aes =
null;
MemoryStream stream =
null;
CryptoStream cryptoStream =
null;
try
{
Rfc2898DeriveBytes rfc2898 =
new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt));
aes =
new AesManaged();
aes.Key = rfc2898.GetBytes(aes.KeySize /
8);
//
设置用于对称算法的密钥
aes.IV = rfc2898.GetBytes(aes.BlockSize /
8);
//
设置用于对称算法的初始化向量(IV)
stream =
new MemoryStream();
//
使用当前的密钥和初始化向量(IV)创建对称加密器对象
cryptoStream =
new CryptoStream(stream, aes.CreateEncryptor(), CryptoStreamMode.Write);
byte[] data = Encoding.UTF8.GetBytes(dataToEncrypt);
cryptoStream.Write(data,
0, data.Length);
cryptoStream.FlushFinalBlock();
return Convert.ToBase64String(stream.ToArray());
}
finally
{
//
关闭当前流并释放与当前流相关的任何资源
if (cryptoStream !=
null){
cryptoStream.Close();
}
if (stream !=
null){
stream.Close();
}
if (aes !=
null){
//
释放资源
aes.Clear();
}
}
}
///
<summary>
///
解密数据
///
</summary>
///
<param name="dataToDecrypt">
需要解密的数据
</param>
///
<param name="password">
密码
</param>
///
<param name="salt">
salt值
</param>
///
<returns></returns>
public
static
string Decrypt(
string dataToDecrypt,
string password,
string salt)
{
AesManaged aes =
null;
MemoryStream stream =
null;
CryptoStream cryptoStream =
null;
try
{
Rfc2898DeriveBytes rfc2898 =
new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt));
aes =
new AesManaged();
aes.Key = rfc2898.GetBytes(aes.KeySize /
8);
//
设置用于对称算法的密钥
aes.IV = rfc2898.GetBytes(aes.BlockSize /
8);
//
设置用于对称算法的初始化向量(IV)
stream =
new MemoryStream();
//
使用当前的密钥和初始化向量(IV)创建对称解密器对象
cryptoStream =
new CryptoStream(stream, aes.CreateDecryptor(), CryptoStreamMode.Write);
byte[] data = Encoding.UTF8.GetBytes(dataToDecrypt);
cryptoStream.Write(data,
0, data.Length);
cryptoStream.FlushFinalBlock();
byte[] decryptBytes = stream.ToArray();
return Encoding.UTF8.GetString(decryptBytes,
0, decryptBytes.Length);
}
finally
{
//
关闭当前流并释放与当前流相关的任何资源
if (cryptoStream !=
null)
{
cryptoStream.Close();
}
if (stream !=
null)
{
stream.Close();
}
if (aes !=
null)
{
//
释放资源
aes.Clear();
}
}
}
}
参考:http://kosmisch.net/archive/2011/10/25/encrypt_data_in_windows_phone_application.aspx