使用delphi+intraweb进行微信开发4—微信消息加解密
示例代码已经放出!请移步使用delphi+intraweb进行微信开发1~4代码示例进行下载,虽为示例代码但是是从我项目中移出来的,封装很完备适于自行扩展和修改。
在上一讲当中我做了个简单的微信文本消息回显应用,当时是以微信明文方式实现的,其实微信推荐的是消息应该加密传输以增加安全性,所以这讲说说微信消息的加解密。
在微信的帮助页面上可以下载微信消息加解密的例程,可惜的是没有Delphi语言的示例,网上搜索一番,没有人贡献出写好的Delphi版的微信加解密算法单元,好在有官方示例的C#版的,那就按照C#的改一个吧。
微信消息是以AES算法进行的加密处理,而遗憾的是Delphi并没有内置的AES算法单元,必须找第三方实现的,不过一般第三方实现的算法都因为种种原因并不完善,需要使用者酌情修改,所以在基础算法支持上Delphi确实和.net以及java这类的开发语言比不了。
呵呵,上网找Delphi版AES算法吧。在在这里要感谢cnpack开发组,他们不但推出一流的delphi开发环境增强组件还有开源组件包cnvcl,这个组件包中有SHA1、AES、MD5等多种算法单元,我打开AES算法单元查看,发现封装的很完美,ECB、CBC模式均支持,呵呵,幸福了
。
参考C#示例代码一通修改测试,省略几昼夜苦干的吐槽终于开花结果:
呵呵,这个或者是网上目前唯一的开源的Delphi版的微信加解密算法单元吧,激动!
,
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
);
;
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 + );
Move(aEncodingAESKeyBts[0], IvBts[0], 16);
], 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() then
codeLen := 16;
strLst := TStringList.Create;
try
ExtractStrings([ 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;
) then
amount_to_pad := block_size;
to amount_to_pad - 1 do
tmp := tmp + pad_chr;
Result := BytesOf(tmp);
end;
begin
aEncodingAESKeyStr := AnsiString(sEncodingAESKey + );
Move(aEncodingAESKeyBts[0], IvBts[0], 16);
Randcode := CreateRandCode(16);
bRand := TEncoding.UTF8.GetBytes(Randcode);
bAppid := TEncoding.UTF8.GetBytes(cpid);
btmpMsg := TEncoding.UTF8.GetBytes(sMsg);
SetLength(bMsgLen, 4);
bMsgLen[0] := (Length(btmpMsg) shr 24) and $FF;
bMsgLen[1] := (Length(btmpMsg) shr 16) and $FF;
bMsgLen[2] := (Length(btmpMsg) shr 8) and $FF;
bMsgLen[3] := Length(btmpMsg) and $FF;
SetLength(bMsg, Length(bRand) + Length(bAppid) + Length(btmpMsg) + Length(bMsgLen));
Move(bRand[0], bMsg[0], Length(bRand));
Move(bMsgLen[0], bMsg[Length(bRand)], Length(bMsgLen));
Move(btmpMsg[0], bMsg[Length(bRand) + Length(bMsgLen)], Length(btmpMsg));
Move(bAppid[0], bMsg[Length(bRand) + Length(bMsgLen) + Length(btmpMsg)], Length(bAppid));
- Length(bMsg) mod 32);
Move(bMsg[0], msg[0], Length(bMsg));
pad := KCS7Encoder(Length(bMsg));
Move(pad[0], msg[Length(bMsg)], Length(pad));
], AesKey, Length(aEncodingAESKeyBts));
Move(IvBts[0], Iv, Length(IvBts));
InputStream := TMemoryStream.Create;
OutputStream := TMemoryStream.Create;
try
InputStream.Write(msg[0], Length(msg));
InputStream.Position := 0;
EncryptAESStreamCBC(InputStream, 0, AesKey, Iv, OutputStream);
Result := string(EncodeBase64(OutputStream.Memory, OutputStream.Size));
finally
InputStream.Free;
OutputStream.Free;
end;
end;
function TWxMsgCrypt.CreateRandCode(codeLen: Integer): string;
var
codeSerial, code: string;
strLst: TStringList;
randValue, i: Integer;
begin
codeSerial := ) then
codeLen := 16;
strLst := TStringList.Create;
try
ExtractStrings([ to codeLen - 1 do
begin
randValue := Random(strLst.Count);
code := code + strLst[randValue];
end;
Result := code;
finally
strLst.Free;
end;
end;
function TWxMsgCrypt.DecryptMsg(const sToken, sTimeStamp, sNonce, sMsgEncrypt, sSigture,
sAppID, sEncodingAESKey: string; var sMsg: string): WXBizMsgCryptErrorCode;
var
ret: WXBizMsgCryptErrorCode;
cpid: string;
function VerifySignature: WXBizMsgCryptErrorCode;
var
hash: string;
aStr: AnsiString;
AL: TStringList;
i: Integer;
begin
AL := TStringList.Create;
try
AL.Add(sToken);
AL.Add(sTimeStamp);
AL.Add(sNonce);
AL.Add(sMsgEncrypt);
AL.Sort;
hash := to AL.Count - 1 do
hash := hash + AL[i];
aStr := AnsiString(hash);
hash := LowerCase(SHA1Print(SHA1StringA(aStr)));
finally
AL.Free;
end;
if (hash = sSigture) then
Result := WXBizMsgCrypt_OK
else
Result := WXBizMsgCrypt_ValidateSignature_Error;
end;
begin
sMsg := ) then
begin
Result := WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey;
Exit;
end;
);
AL.Add(wxNonce);
AL.Sort;
hash := to AL.Count - 1 do
hash := hash + AL[i];
aStr := AnsiString(hash);
hash := LowerCase(SHA1Print(SHA1StringA(aStr)));
finally
AL.Free;
end;
Result := hash;
end;
begin
sMsgEncrypt := ) then
begin
Result := WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey;
Exit;
end;
//encrypt
try
EncryptField := AES_encrypt(sEncodingAESKey, sMsg, sAppID);
except
on E: Exception do
begin
if E.Message = '1' then
Result := WXBizMsgCrypt_DecryptAES_Error
else
Result := WXBizMsgCrypt_EncryptAES_Error;
Exit;
end;
end;
//gen signature
try
hash := GenSignature;
except
Result := WXBizMsgCrypt_ComputeSignature_Error;
Exit;
end;
//xml
sMsgEncrypt := '<xml><Encrypt><![CDATA[' + EncryptField + ']]></Encrypt>' +
'<MsgSignature><![CDATA[' + hash + ']]></MsgSignature>' +
'<TimeStamp><![CDATA[' + wxDt + ']]></TimeStamp>' +
'<Nonce><![CDATA[' + wxNonce + ']]></Nonce></xml>';
Result := WXBizMsgCrypt_OK;
end;
end.
呵呵,看看效果图吧:


使用delphi+intraweb进行微信开发4—微信消息加解密的更多相关文章
- thinkphp微信开发:安全模式消息加解密
使用thinkphp官方的WeChat包,使用不同模式可以成功,但是安全模式就是不行,现将分析解决结果做下记录. TRight 分析问题: 解密微信服务器消息老是不成功,下载下微信公众平台官方给出的解 ...
- [微信开发利器]微信内移动前端开发抓包调试工具fiddler使用教程
[微信开发利器]微信内移动前端开发抓包调试工具fiddler使用教程 在朋友圈看到一款疯转的H5小游戏,想要copy,什么?只能在微信里打开?小样,图样图森破,限制了oauth.微信浏览器内打开, ...
- php 微信开发之 微信支付 V3 开发 -CURLOP_TIMEOUT问题
如果不懂怎么配置的话请看文章 php 微信开发之 微信支付配置 基本配置后在继续本文章的开发 . 本文章就先继续基本的实现!也并不困难.我大概的思路的返回购买者的唯一id 和 订单号的唯一 id 就2 ...
- 微信开发_微信教程__微信通讯框架V1.0
做个广告先, PHP千人群(6848027) C++群 (1414577) 看雪汇编&反汇编群(15375777) 看雪汇编&反汇编2群(4915800) 转载不一定注明出处,只要推荐 ...
- 微信开发:微信js_sdk 分享,前端部分(二)
微信开发:微信js-sdk前端分享,代码如下: <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"> ...
- asp.net微信开发第二篇----消息应答
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上. 请注意: 1.关于重试的消息排重,推荐使用msgid排重. 2.微信服务器在五秒内收不到响应会断掉连接 ...
- 使用delphi+intraweb进行微信开发3—微信消息处理
示例代码已经放出!请移步使用delphi+intraweb进行微信开发1~4代码示例进行下载,虽为示例代码但是是从我项目中移出来的,封装很完备适于自行扩展和修改. 在第二讲使用delphi+intra ...
- 【微信开发】微信公众平台接入及绑定提示“请求URL超时”的解决办法
成为微信开发者的第一步--微信公众平台接入 第一步:填写服务器配置 在开发->基本配置处启用服务器配置.修改配置 其中URL是开发者用来接收微信消息和事件的接口URL. Token可由开发者可以 ...
- 微信开发(2)---微信小程序开发实战part1
微信开发现在来说,简单可以概括为两部分,微信公众号和微信小程序. 微信公众号的技术已经非常成熟.分为服务号和订阅号.简单的.可以弄一个个人订阅号,在编辑模式下就可以实现推送图文.自动回复.自定义菜单的 ...
随机推荐
- 如何隐藏UITableView中的一项
我最近工作中的一个iOS App中经常有在不同的场合,隐现菜单列表里某一项的需求.如果初始化的时候就去掉某一项的话,有可能让序号变化, 处理上会比较麻烦容易出错.我采用了初始化列表相同但是隐藏sect ...
- 使用ehcache持久化数据到磁盘 并且在应用服务器重启后不丢失数据
使用ehcache时如何持久化数据到磁盘,并且在应用服务器重启后不丢失数据1.如何持久化到磁盘使用cache.flush(),每次写入到cache后调用cache.flush() ,这样ehcache ...
- SQL Server 2008 R2 未能加载文件或程序集Microsoft.SqlServer.Sqm...
错误提示:未能加载文件或程序集“Microsoft.SqlServer.Sqm, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8 ...
- LeakCanary Android 和 Java 内存泄露检测。
开始使用 在 build.gradle 中加入引用,不同的编译使用不同的引用: dependencies { debugCompile 'com.squareup.leakcanary:leakcan ...
- Java中对session的简单操作
1.jsp中操作session <% String name=(String)request.getSession().getAttribute("username"); / ...
- linux 下调试 汇编
gcc: -c 编译后汇编,不连接 -S 编译后停止,不进行汇编 -o 编译,汇编,连接 -g 生成调试信息 -gstabs 标识符 main gdb break *标识符 :设置断点 info re ...
- 编译.NET项目的时候报错错误“ResGen.exe”已退出,代码为 -1073741701
解决的办法如下: 1.关闭所有Visual Studio: 2.以管理员的身份打开命令提示窗口:(开始-运行-cmd) //有人说要使用vs tools 里面的控制台 亲试无卵用 3. ...
- linux性能指令分析进阶篇
作为刚刚走入测试领域的我来说,对性能测试了解的也不是很深,只不过自己平常一直在收集资料,性能测试也没有那么神秘,也请广大测试小白不要陷入误区,其实性能测试跟功能测试关系并不大,即使你做10年功能测试, ...
- CocoaPods报错:The dependency `Alamofire ` is not used in any concrete target
看到这个错误提示,首先看看自己的版本是不是 OS X EI Capitan,也就是10.10以后的版本,因为这个版本是比较新的版本,网络上找的那些安装cocoapod命令其实有些过时了,特别是创建po ...
- Android proguard 详解
本文转载于:http://blog.csdn.net/banketree/article/details/41928175 简介 Java代码是非常容易反编译的.为了很好的保护Java源代码,我们往往 ...