示例代码已经放出!请移步进行下载,虽为示例代码但是是从我项目中移出来的,封装很完备适于自行扩展和修改。
在上一讲当中我做了个简单的微信文本消息回显应用,当时是以微信明文方式实现的,其实微信推荐的是消息应该加密传输以增加安全性,所以这讲说说微信消息的加解密。
在微信的帮助页面上可以下载微信消息加解密的例程,可惜的是没有Delphi语言的示例,网上搜索一番,没有人贡献出写好的Delphi版的微信加解密算法单元,好在有官方示例的C#版的,那就按照C#的改一个吧。
微信消息是以AES算法进行的加密处理,而遗憾的是Delphi并没有内置的AES算法单元,必须找第三方实现的,不过一般第三方实现的算法都因为种种原因并不完善,需要使用者酌情修改,所以在基础算法支持上Delphi确实和.net以及java这类的开发语言比不了。
呵呵,上网找Delphi版AES算法吧。在在这里要感谢cnpack开发组,他们不但推出一流的delphi开发环境增强组件还有开源组件包cnvcl,这个组件包中有SHA1、AES、MD5等多种算法单元,我打开AES算法单元查看,发现封装的很完美,ECB、CBC模式均支持,呵呵,幸福了。
参考C#示例代码一通修改测试,省略几昼夜苦干的吐槽终于开花结果:
呵呵,这个或者是网上目前唯一的开源的Delphi版的微信加解密算法单元吧,激动!
{*****************************************************************************} { } { 泛思微平台 } { } { 版权所有 (C) 2016 石家庄泛思电子商务有限公司 } { } { 微信消息加密解密单元,使用DelphiXE2版本编写 } { 作者:Delphi力量 } { QQ:404328970 } { EMail: [email protected] } { Blog:www.cnblogs.com/dpower } { 参考链接: } { http://mp.weixin.qq.com/wiki/14/70e73cedf9fd958d2e23264ba9333ad2.html } { } {*****************************************************************************}
unit uWxMsgCrypt;
interface
uses System.Classes, System.SysUtils;
type WXBizMsgCryptErrorCode = ( WXBizMsgCrypt_OK = 0, WXBizMsgCrypt_ValidateSignature_Error = -40001, WXBizMsgCrypt_ParseXml_Error = -40002, WXBizMsgCrypt_ComputeSignature_Error = -40003, WXBizMsgCrypt_IllegalAesKey = -40004, WXBizMsgCrypt_ValidateAppid_Error = -40005, WXBizMsgCrypt_EncryptAES_Error = -40006, WXBizMsgCrypt_DecryptAES_Error = -40007, WXBizMsgCrypt_IllegalBuffer = -40008, WXBizMsgCrypt_EncodeBase64_Error = -40009, WXBizMsgCrypt_DecodeBase64_Error = -40010 );
/// <summary> /// 提供微信加密消息解密和微信明文消息加密功能 /// </summary> TWxMsgCrypt = class private function CreateRandCode(codeLen: Integer): string; function AES_decrypt(const sEncodingAESKey, sMsgEncrypt: string; var cpid: string): string; function AES_encrypt(const sEncodingAESKey, sMsg, cpid: string): string; public /// <summary> /// 解密微信消息 /// </summary> /// <param name="sToken">Token,看公众号设置</param> /// <param name="sTimeStamp">时间戳,随微信消息一起传入,可以通过Url参数获取</param> /// <param name="sNonce">随机字符串,随微信消息一起传入,可以通过Url参数获取</param> /// <param name="sMsgEncrypt">微信消息xml的Encrypt字段内容</param> /// <param name="sSigture">签名,随微信消息一起传入,可以通过Url参数获取</param> /// <param name="sAppID">AppID,看公众号设置</param> /// <param name="sEncodingAESKey">EncodingAESKey,看公众号设置</param> /// <param name="sMsg">sMsg: 解密后的Encrypt字段内容原文,当return返回WXBizMsgCrypt_OK时有效</param> /// <returns>成功WXBizMsgCrypt_OK,失败返回对应的错误码</returns> function DecryptMsg(const sToken, sTimeStamp, sNonce, sMsgEncrypt, sSigture, sAppID, sEncodingAESKey: string; var sMsg: string): WXBizMsgCryptErrorCode;
/// <summary> /// 加密微信消息 /// </summary> /// <param name="sMsg">全部xml内容(明文)</param> /// <param name="sAppID">AppID,看公众号设置</param> /// <param name="sEncodingAESKey">EncodingAESKey,看公众号设置</param> /// <param name="sMsgEncrypt">sMsgEncrypt: 输出的是加密后的全部xml(可以直接发送无需再编组xml),当return返回WXBizMsgCrypt_OK时有效</param> /// <returns>成功WXBizMsgCrypt_OK,失败返回对应的错误码</returns> function EncryptMsg(const sMsg, sToken, sAppID, sEncodingAESKey: string; var sMsgEncrypt: string): WXBizMsgCryptErrorCode; end;
implementation
uses CnSHA1, EncdDecd, CnAES, System.Math, uWxGlobal;
{ TWxMsgCrypt }
function TWxMsgCrypt.AES_decrypt(const sEncodingAESKey, sMsgEncrypt: string; var cpid: string): string; var aEncodingAESKeyStr, sInput: AnsiString; aEncodingAESKeyBts, IvBts, InputBts: TBytes; InputStream, DecodeStream: TMemoryStream; AesKey: TAESKey256; Iv: TAESBuffer; P: PByteArray; iLen, iDecodeDataLen: Integer; bMsg, bAppid: TBytes;
function GetRealDataLenWithoutKCS7Bytes: Integer; var lstBt: Byte; block_size, AllKCS7ByteCount: Integer; begin block_size := 32; lstBt := P^[DecodeStream.Size - 1]; AllKCS7ByteCount := block_size - (block_size - Ord(lstBt)); if (AllKCS7ByteCount > 0) and (AllKCS7ByteCount < DecodeStream.Size) then begin if P^[DecodeStream.Size - AllKCS7ByteCount] = lstBt then Result := DecodeStream.Size - AllKCS7ByteCount else Result := DecodeStream.Size; end else Result := DecodeStream.Size; end;
begin try aEncodingAESKeyStr := AnsiString(sEncodingAESKey + '='); aEncodingAESKeyBts := DecodeBase64(aEncodingAESKeyStr); except raise Exception.Create('1'); end; try SetLength(IvBts, 16); Move(aEncodingAESKeyBts[0], IvBts[0], 16);
// aes.KeySize = 256; aes.BlockSize = 128; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.None; sInput := AnsiString(sMsgEncrypt); InputBts := DecodeBase64(sInput);
InputStream := TMemoryStream.Create; DecodeStream := TMemoryStream.Create; try InputStream.Write(InputBts[0], Length(InputBts)); Move(aEncodingAESKeyBts[0], AesKey, Length(aEncodingAESKeyBts)); Move(IvBts[0], Iv, Length(IvBts)); InputStream.Position := 0; DecryptAESStreamCBC(InputStream, 0, AesKey, Iv, DecodeStream); P := PByteArray(DecodeStream.Memory); iDecodeDataLen := GetRealDataLenWithoutKCS7Bytes;
iLen := P^[16] shl 24 + P^[17] shl 16 + P^[18] shl 8 + P^[19]; SetLength(bMsg, iLen); SetLength(bAppid, iDecodeDataLen - 20 - iLen); Move(P^[20], bMsg[0], iLen); Move(P^[20 + iLen], bAppid[0], iDecodeDataLen - 20 - iLen); Result := TEncoding.UTF8.GetString(bMsg); cpid := TEncoding.UTF8.GetString(bAppid); finally InputStream.Free; DecodeStream.Free; end; except raise Exception.Create('2'); end; end;
function TWxMsgCrypt.AES_encrypt(const sEncodingAESKey, sMsg, cpid: string): string; var aEncodingAESKeyStr: AnsiString; aEncodingAESKeyBts, IvBts, bRand, bAppid, btmpMsg, bMsg, bMsgLen, msg, pad: TBytes; Randcode: string; AesKey: TAESKey256; Iv: TAESBuffer; InputStream, OutputStream: TMemoryStream;
function CreateRandCode(codeLen: Integer): string; var codeSerial, code: string; strLst: TStringList; randValue, i: Integer; begin codeSerial := '2,3,4,5,6,7,a,c,d,e,f,h,i,j,k,m,n,p,r,s,t,A,C,D,E,F,G,H,J,K,M,N,P,Q,R,S,U,V,W,X,Y,Z'; if (codeLen = 0) then codeLen := 16; strLst := TStringList.Create; try ExtractStrings([','], [], PChar(codeSerial), strLst); code := ''; Randomize; for i := 0 to codeLen - 1 do begin randValue := Random(strLst.Count); code := code + strLst[randValue]; end; Result := code; finally strLst.Free; end; end;
function KCS7Encoder(text_length: Integer): TBytes; var block_size, amount_to_pad: Integer; pad_chr: Char; tmp: string; i: Integer; begin block_size := 32; // 计算需要填充的位数 amount_to_pad := block_size - (text_length mod block_size); if (amount_to_pad = 0) then amount_to_pad := block_size; // 获得补位所用的字符 pad_chr := Chr(amount_to_pad); tmp := ''; for i := 0 to amount_to_pad - 1 do tmp := tmp + pad_chr; Result := BytesOf(tmp); end;
begin aEncodingAESKeyStr := AnsiString(sEncodingAESKey + '='); aEncodingAESKeyBts := DecodeBase64(aEncodingAESKeyStr);
SetLength(IvBts
-
六六分期app的软件客服如何联系?不知道吗?加qq群【895510560】即可!标题:六六分期
阅读:19121|2023-10-27
-
今天小编告诉大家如何处理win10系统火狐flash插件总是崩溃的问题,可能很多用户都不知
阅读:9971|2022-11-06
-
今天小编告诉大家如何对win10系统删除桌面回收站图标进行设置,可能很多用户都不知道
阅读:8317|2022-11-06
-
今天小编告诉大家如何对win10系统电脑设置节能降温的设置方法,想必大家都遇到过需要
阅读:8686|2022-11-06
-
我们在使用xp系统的过程中,经常需要对xp系统无线网络安装向导设置进行设置,可能很多
阅读:8626|2022-11-06
-
今天小编告诉大家如何处理win7系统玩cf老是与主机连接不稳定的问题,可能很多用户都不
阅读:9643|2022-11-06
-
电脑对日常生活的重要性小编就不多说了,可是一旦碰到win7系统设置cf烟雾头的问题,很
阅读:8611|2022-11-06
-
我们在日常使用电脑的时候,有的小伙伴们可能在打开应用的时候会遇见提示应用程序无法
阅读:7991|2022-11-06
-
今天小编告诉大家如何对win7系统打开vcf文件进行设置,可能很多用户都不知道怎么对win
阅读:8639|2022-11-06
-
今天小编告诉大家如何对win10系统s4开启USB调试模式进行设置,可能很多用户都不知道怎
阅读:7527|2022-11-06
|
请发表评论