本人菜鸟一枚,大学里凭兴趣学了一点WP的皮毛,后来又幸运(或者不幸)的进了一家专注于Windows生态的公司做了一段时间的UWP。在博客园写点自己遇到的东西,作为分享,也作为自己的备忘,如果有错误的地方,或者可以提升B格的地方,希望园子里的大神们不吝赐教。
初进公司时,公司要做支付相关的业务,需要和支付宝、优易付、爱贝等支付渠道对接,对新手的我来说,加密或者是签名简直难到死,学校里哪用过这个,OMG,只能迎着头皮找资料。
这里我想请教大家一个问题,就是如何学习。例如当你遇到一个陌生的东西,你是如何查找资料解决问题的?当我需要做加密的时候我的做法是打开百度搜索“WP 3des加密”,这样找出来的结果基本都不能用。。。后来终于在博客园看到了两篇相关的博客,我才知道原来要实现相关功能需要哪几个类哪几个方法,这个过程大概用了一周吧,效率超低。
解决我燃眉之急的两篇博客分别是:
王磊:http://www.cnblogs.com/webabcd/archive/2013/06/03/3114657.html
老周:http://www.cnblogs.com/tcjiaan/p/4303918.html
看了这两篇博客就知道该使用哪些类了,再接下来就相对简单了。非常感谢两位老师的分享和指导。
在RT应用中,涉及到加/解密的API都在以下几个命名空间里:
1、Windows.Security.Cryptography
2、Windows.Security.Cryptography.Core
3、Windows.Security.Cryptography.DataProtection
接下来分享一下我在项目中做过的几个加密/签名,进行了一下简单的封装,还望大家指点
1.3des加密
internal sealed class TripleDesEncryptHelper{//加/解密 第一步 //通过SymmetricKeyAlgorithmProvider的静态方法OpenAlgorithm()得到一个SymmetricKeyAlgorithmProvider实例//该方法参数是要使用的加/解密算法的名字internal static SymmetricKeyAlgorithmProvider syprd = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.TripleDesEcb);/// <summary>/// 加密函数/// </summary>/// <param name="data">需要加密的字符串</param>/// <returns>返回加密后的结果</returns>public static string Encrypt(string data, string key){string encryptedData = null;try{byte[] dataBytes = Encoding.UTF8.GetBytes(data);//这里我自己写了一个pkcs5对齐,不过后来有看到过C#pkcs5和pkcs7是一样的说法,有待验证byte[] pkcs5databytes = pkcs5(dataBytes);IBuffer databuffer = pkcs5databytes.AsBuffer();byte[] keyBytes = Convert.FromBase64String(key);IBuffer keybuffer = keyBytes.AsBuffer();//构造CryptographicKeyCryptographicKey cryptographicKey = syprd.CreateSymmetricKey(keybuffer);//加密//Encrypt需要三个参数分别为加密使用的Key,需要加密的Data,以及向量IV//Des加密中Ecb模式和Cbc模式的区别就在于是否必须使用向量IVIBuffer cryptBuffer = CryptographicEngine.Encrypt(cryptographicKey, databuffer, null); **************/byte[] enctyptedBytes = cryptBuffer.ToArray();//进行base64编码encryptedData = Convert.ToBase64String(enctyptedBytes); }catch (Exception ex){DebugHelper.Log("TripleDesEncryptHelper.Encrypt", ex.Message);}return encryptedData.Trim();}/// <summary>/// 解密函数/// </summary>/// <param name="data">待解密的字符串</param>/// <returns>解密后的数据</returns>public static string Decrypt(string data, string key){string decryptedData = null;try{byte[] dataBytes = Convert.FromBase64String(data);IBuffer dataBuffer = dataBytes.AsBuffer();byte[] keyBytes = Convert.FromBase64String(key);IBuffer keybuffer = keyBytes.AsBuffer();CryptographicKey cryptographicKey = syprd.CreateSymmetricKey(keybuffer);IBuffer decryptedBuffer = CryptographicEngine.Decrypt(cryptographicKey, dataBuffer, null);decryptedData = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, decryptedBuffer);//防止乱码var result = System.Text.RegularExpressions.Regex.Match(decryptedData, "[a-zA-Z0-9]*");decryptedData = result.ToString();}catch (Exception ex){DebugHelper.Log("TripleDesEncryptHelper.Decrypt", ex.Message);}return decryptedData;}/// <summary>/// 把数据进行pkcs5对齐/// </summary>/// <param name="databytes">待处理的数据</param>/// <returns></returns>private static byte[] pkcs5(byte[] databytes){byte[] newBytes = null;int datalength = databytes.Length;int blocksize = (int)syprd.BlockLength;if (!(datalength % blocksize == 0)){int need = blocksize - (datalength % 8);newBytes = new byte[datalength + need];for (int i = 0; i < datalength; i++){newBytes[i] = databytes[i];}byte xx = 0x0;switch (need){case 1:xx = 0x1;break;case 2:xx = 0x2;break;case 3:xx = 0x3;break;case 4:xx = 0x4;break;case 5:xx = 0x5;break;case 6:xx = 0x6;break;case 7:xx = 0x7;break;}for (int i = 0; i < need; i++){newBytes[datalength + i] = xx;}}else{newBytes = new byte[datalength + 8];for (int i = 0; i < datalength; i++){newBytes[i] = databytes[i];}byte xx = 0x8;for (int i = 0; i < 8; i++){newBytes[datalength + i] = xx;}}return newBytes;} }
2. Sha1签名
根据爱贝的要求,需要先将数据进行sha1 hash,再将hash后的数据进行sha1签名
internal sealed class Sha1SignHelper{/// <summary>/// 用sha1进行签名/// </summary>/// <param name="data">需要签名的数据</param>/// <param name="key">签名私钥</param>/// <returns></returns>internal static string Sha1Sign(string data, string key){string signedData = null;IBuffer dataBuffer = Encoding.UTF8.GetBytes(data).AsBuffer();try{AsymmetricKeyAlgorithmProvider asymmetricAlgorithm = AsymmetricKeyAlgorithmProvider.OpenAlgorithm("RSASIGN_PKCS1_SHA1");//创建一个公钥私钥对CryptographicKey KeyPair = asymmetricAlgorithm.ImportKeyPair(CryptographicBuffer.DecodeFromBase64String(key), CryptographicPrivateKeyBlobType.Pkcs1RsaPrivateKey);//哈希计算dataHashAlgorithmProvider provider = HashAlgorithmProvider.OpenAlgorithm(Windows.Security.Cryptography.Core.HashAlgorithmNames.Sha1);IBuffer hashedData = provider.HashData(dataBuffer);//签名IBuffer signedHashedBuffer = CryptographicEngine.SignHashedData(KeyPair, hashedData);signedData = CryptographicBuffer.EncodeToBase64String(signedHashedBuffer);}catch (Exception ex){DebugHelper.Log("Sha1SignHelper.Sha1Sign", ex.Message);}return signedData;}internal static bool Sha1VerifySignature(string oldText, string signature, string publicKey){bool dataCorrect = false;try{AsymmetricKeyAlgorithmProvider asymmetricAlgorithm = AsymmetricKeyAlgorithmProvider.OpenAlgorithm("RSASIGN_PKCS1_SHA1");//创建一个公钥私钥对IBuffer pubKeyBuffer = Convert.FromBase64String(publicKey).AsBuffer();CryptographicKey KeyPair = asymmetricAlgorithm.ImportPublicKey(CryptographicBuffer.DecodeFromBase64String(publicKey));// 验证签名(通过公钥)IBuffer databuffer = CryptographicBuffer.ConvertStringToBinary(oldText, BinaryStringEncoding.Utf8); ;dataCorrect = CryptographicEngine.VerifySignature(KeyPair, databuffer, Convert.FromBase64String(signature).AsBuffer());}catch (Exception ex){DebugHelper.Log("Sha1SignHelper.Sha1VerifySignature", ex.Message);}return dataCorrect;}}
对接过支付宝的大神们应该比较熟悉,支付宝与爱贝的区别就在于支付宝是先md5哈希,再sha1签名,可是我将
HashAlgorithmProvider provider = HashAlgorithmProvider.OpenAlgorithm(Windows.Security.Cryptography.Core.HashAlgorithmNames.Sha1);
改为
HashAlgorithmProvider provider = HashAlgorithmProvider.OpenAlgorithm(Windows.Security.Cryptography.Core.HashAlgorithmNames.Md5);
签名后得到的数据却始终与支付宝匹配不上,无奈只能在服务器上完成这一环节,有知道问题所在的大神们可以指点一下。
以上就是我在做支付时用到过的加密/签名算法,自己封装成了类以便使用。
做完这个项目后其实我对加密/签名算法本身还是一头雾水,并不理解算法的本质原理,只是完成了功能而已,所以过程中也遇到了几个问题:
1.永远sha1签名的私钥的格式 CryptographicKey KeyPair = asymmetricAlgorithm.ImportKeyPair(CryptographicBuffer.DecodeFromBase64String(key), CryptographicPrivateKeyBlobType.Pkcs1RsaPrivateKey)中CryptographicPrivateKeyBlobType.Pkcs1RsaPrivateKey和CryptographicPrivateKeyBlobType.Pkcs8RawPrivateKeyInfo的区别
2.pem格式密钥和xml格式密钥怎么转换
3.为什么先md5哈希再rsa签名始终和支付宝对不上?
如果有理解深入的大神,希望可以指点一下。
第一次写博客,可能思路不清晰,望见谅!