zoukankan      html  css  js  c++  java
  • 【WP开发】加密篇:双向加密

    本文转载自:http://www.cnblogs.com/tcjiaan/p/4303918.html

    说起双向加密,如果以前在.NET开发中弄过加/解密的朋友都不会陌生,常用的算法有DES、AES等。在RT应用程序中,也提供了加密相关的API,算法自然是一样的,只是API的封装方式不同罢了,因为RT不完全是托管代码,而又类似于COM的形式公开,这对于低端设备来说,性能可以提升,当然了,对于高端设备来说无所谓。

    在WP的RT应用中,涉及到加/解密的API都在以下几个命名空间里,大家要用的就在里面找,也不是所有类都会用得上,加密一般就用两大类:需要恢复内容时选用双向加密,如DES、AES等算法;如果不需要还原被加密的内容,就用大家严重熟悉的MD5等哈希算法。比如密码。

    1、Windows.Security.Cryptography

    2、Windows.Security.Cryptography.Core

    3、Windows.Security.Cryptography.DataProtection

    其中,DataProtection下所用的是系统实现的算法来加密和解密数据,比较方便,但不方便传输,比较适合在本机使用,不适宜加密和解密通过网络传输的加密数据,通用性不那么强。

    今天先给大家简单介绍一下双向加密,我这个人性格比较坏,不喜欢一个类一个类地去介绍,然后列个表格说这个类有哪些属性,方法之类的写作方式。我比较BS那些老是抄MSDN的人。因此,不要指望我会机械式地给你讲解,老周不喜欢这样,老周向来对实例讲述情有独衷。

    不过呢,一些必要的口水还是要的,不管你使用哪种算法来加密和解密数据,都要用到CryptographicEngine类,这个类人品值很高,是静态的,加密解密时直接调用它的方法即可,不用new它的实例。加密时调用Encrypt方法,解密时调用Decrypt方法。

    双向加密通常要准备两个东西,一个是密钥Key,一个是初始向量iv,iv不是必须的,但key是不可少的。加密时用的key和iv,而在解密时也要用与加密时相同的key和iv才能解密。这个相信不用我废话了,这是小学一年级的常识。

    接下来说说步骤:

    第一步,通过SymmetricKeyAlgorithmProvider的静态方法OpenAlgorithm()得到一个SymmetricKeyAlgorithmProvider实例,方法参数是要使用的加/解密算法的名字,这个字符串不用我们去猜怎么写,直接通过SymmetricAlgorithmNames的静态属性就能返回算法的相应名字。

    SymmetricKeyAlgorithmProvider syprd = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.DesCbc);

    第二步,创建key,其实key是一组字节,我这个例子是以DES算法为例,key是64位,即8个字节,这些字节怎么生成,大家自己发挥个人想象力吧,为了简单,我直接用12345678来充当这8个字节。

        // 表示Key的字节数组
        byte[] keyBtArray = { 1, 2, 3, 4, 5, 6, 7, 8 };
        // 表示初始向量(iv)的字节数组
        byte[] ivBtArray = { 1, 2, 3, 4, 5, 6, 7, 8 };
        // 表示加/解密的密钥的对象
        CryptographicKey myKey = null;
    

    产生key的方法是调用刚才创建的SymmetricKeyAlgorithmProvider实例的CreateSymmetricKey方法。这里我先给大家说明一个情况。由于RT API里面在处理字节缓冲区时常用到IBuffer,实现接口类型为Buffer类。故.net的API中为byte[]定义了一个扩展方法,通过AsBuffer方法可以产生Buffer对象。

            IBuffer keybuffer = keyBtArray.AsBuffer();
            myKey = syprd.CreateSymmetricKey(keybuffer);
    

    第三步,加密。加密很简单,直接调用CryptographicEngine.Encrypt方法就可以了,返回的是加密后的数据。

            // 进行加密
            this.cryptBuffer = CryptographicEngine.Encrypt(myKey, txtBuffer, ivBtArray.AsBuffer());
    

    第四步,解密。解密也是简单地调用。

            // 解密
            IBuffer decryptBuffer = CryptographicEngine.Decrypt(myKey, this.cryptBuffer, ivBtArray.AsBuffer());
    

    本例子是让用户在TextBox中输入文本,先将文本加密,然后再解密,并显示解密后的文本。

    <StackPanel>
            <StackPanel.Resources>
                <Style TargetType="TextBlock">
                    <Setter Property="FontSize" Value="22"/>
                </Style>
            </StackPanel.Resources>
            <TextBlock Text="请输入待加密内容:"/>
            <TextBox Name="txtInput"/>
            <Button Margin="0,25,0,0" Content="加密" Click="OnEncryptClick"/>
            <Button Click="OnDecryptoClick">解密</Button>
            <TextBlock Margin="0,25,0,0" Text="解密后:"/>
            <TextBlock Name="tbDecrypto" FontSize="28" Foreground="SkyBlue"/>
        </StackPanel>
       private async void OnEncryptClick(object sender, RoutedEventArgs e)
            {
                // 将输入的文本转换为字节缓冲区
                IBuffer txtBuffer = CryptographicBuffer.ConvertStringToBinary(txtInput.Text, BinaryStringEncoding.Utf8);
                Button b = sender as Button;
                b.IsEnabled = false;
                // 进行加密
                this.cryptBuffer = CryptographicEngine.Encrypt(myKey, txtBuffer, ivBtArray.AsBuffer());
                Windows.UI.Popups.MessageDialog msgdlg = new Windows.UI.Popups.MessageDialog("加密完成。");
                await msgdlg.ShowAsync();
                b.IsEnabled = true;
            }
    
            private async void OnDecryptoClick(object sender, RoutedEventArgs e)
            {
                Button b = sender as Button;
                b.IsEnabled = false;
                // 解密
                IBuffer decryptBuffer = CryptographicEngine.Decrypt(myKey, this.cryptBuffer, ivBtArray.AsBuffer());
                tbDecrypto.Text = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, decryptBuffer);
                Windows.UI.Popups.MessageDialog msgbox = new Windows.UI.Popups.MessageDialog("解密完成。");
                await msgbox.ShowAsync();
                b.IsEnabled = true;
            }

    要将文本转换为Buffer,可以用CryptographicBuffer.ConvertStringToBinary方法;反过来可以用CryptographicBuffer.ConvertBinaryToString,编码方式一般用utf-8,这样通用性好。

    似乎一切就绪,但动行后,在加密时会发生异常,提示输入的缓冲区无效。这个错误很多人都遇到,我看到在MSDN社区上有不少朋友提问,其他社区上也有,不管用的DES还是AES算法。为什么加密时会出错呢?

    那是因为加密处理的字节块没有对齐导致的。可以用以下代码来获得某种加密算法的块大小。

    System.Diagnostics.Debug.WriteLine(“块大小:” + syprd.BlockLength);

    就是SymmetricKeyAlgorithmProvider实例的BlockLength属性,DES算法输出以下结果:
    这里写图片描述

    8就是8个字节,如果要加密的数据的字节总数不是8的倍数的话就会出错,如果被加密的数据大小为16字节,可以被8整除,不会出错,如果是23,不能被8整除,就会发生异常。

    好,找到原因了,解决起来就有针对性了,一种方法是你自己动手,想办法把被加密的数据的长度弄成8的倍数。比如23字节,你就想办法加一个字节,让它变成24个字节。

    其实嘛,有一种方法更简单,就是让算法自己去填充,方法是在new出SymmetricKeyAlgorithmProvider实例,我们原来用的是SymmetricAlgorithmNames.DesCbc,把它改为SymmetricAlgorithmNames.DesCbcPkcs7就行了。因为Pkcs7模式会自动填充字节块。

     SymmetricKeyAlgorithmProvider syprd = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.DesCbcPkcs7);
    

    这样一改,加密时就不会出错,因为字节块被自动填充。

    看看运行结果:
    这里写图片描述
    AES的加密解密也与DES类似。

    看看时间,差不多开饭了,先说到这里吧,下一篇咱们聊聊单向加密吧。

  • 相关阅读:
    用友软件T3出纳通提示单据锁定
    保存单据时提示“计量单位组不正确”
    cxgrid导出数据的格式设置(转载)
    会话打印机不会自动删除解决方法
    用友U8总账对账不平问题总结
    存货核算期初无法从库存取数
    SQL Server 2000 数据库日志太大!如何管理,清除,变小,压缩它
    Delphi控件cxGrid 如何动态创建列?
    关于Treeview 选中节点高亮有关问题
    U8远程接入客户端重新安装问题
  • 原文地址:https://www.cnblogs.com/ggzone/p/10121297.html
Copyright © 2011-2022 走看看