示例代码已经放出!请移步使用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: stringvar 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—微信消息加解密的更多相关文章

  1. thinkphp微信开发:安全模式消息加解密

    使用thinkphp官方的WeChat包,使用不同模式可以成功,但是安全模式就是不行,现将分析解决结果做下记录. TRight 分析问题: 解密微信服务器消息老是不成功,下载下微信公众平台官方给出的解 ...

  2. [微信开发利器]微信内移动前端开发抓包调试工具fiddler使用教程

    [微信开发利器]微信内移动前端开发抓包调试工具fiddler使用教程   在朋友圈看到一款疯转的H5小游戏,想要copy,什么?只能在微信里打开?小样,图样图森破,限制了oauth.微信浏览器内打开, ...

  3. php 微信开发之 微信支付 V3 开发 -CURLOP_TIMEOUT问题

    如果不懂怎么配置的话请看文章 php 微信开发之 微信支付配置 基本配置后在继续本文章的开发 . 本文章就先继续基本的实现!也并不困难.我大概的思路的返回购买者的唯一id 和 订单号的唯一 id 就2 ...

  4. 微信开发_微信教程__微信通讯框架V1.0

    做个广告先, PHP千人群(6848027) C++群 (1414577) 看雪汇编&反汇编群(15375777) 看雪汇编&反汇编2群(4915800) 转载不一定注明出处,只要推荐 ...

  5. 微信开发:微信js_sdk 分享,前端部分(二)

    微信开发:微信js-sdk前端分享,代码如下: <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"> ...

  6. asp.net微信开发第二篇----消息应答

    当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上. 请注意: 1.关于重试的消息排重,推荐使用msgid排重. 2.微信服务器在五秒内收不到响应会断掉连接 ...

  7. 使用delphi+intraweb进行微信开发3—微信消息处理

    示例代码已经放出!请移步使用delphi+intraweb进行微信开发1~4代码示例进行下载,虽为示例代码但是是从我项目中移出来的,封装很完备适于自行扩展和修改. 在第二讲使用delphi+intra ...

  8. 【微信开发】微信公众平台接入及绑定提示“请求URL超时”的解决办法

    成为微信开发者的第一步--微信公众平台接入 第一步:填写服务器配置 在开发->基本配置处启用服务器配置.修改配置 其中URL是开发者用来接收微信消息和事件的接口URL. Token可由开发者可以 ...

  9. 微信开发(2)---微信小程序开发实战part1

    微信开发现在来说,简单可以概括为两部分,微信公众号和微信小程序. 微信公众号的技术已经非常成熟.分为服务号和订阅号.简单的.可以弄一个个人订阅号,在编辑模式下就可以实现推送图文.自动回复.自定义菜单的 ...

随机推荐

  1. 行列式计算(C#)

    最近几天学习高等代数老师说要写个程序算行列式的结果,闲来无事就简单写了一下. 不多说了,上代码 using System; using System.Collections.Generic; usin ...

  2. 根据内存布局定位的一个fastdfs坑

    在使用fastdfs时,编写数据上传代码时,遇到一个坑.最终根据指针对应的内存布局定位到一个其client API的一个坑,值得记录一下.具体是在 tracker_connect_server() 这 ...

  3. RAF(RandomAccessFile)类

    作用:读取文件 /** * */ package com.io.file; import java.io.File; import java.io.IOException; import java.i ...

  4. thinkphp在模型中自动完成session赋值

    相信用过thinkphp的用户都知道thinkphp的模型可以完成很多辅助功能,比 如自动验证.自动完成等,今天在开发中遇到自动完成中需要获取session值 然后自动赋值的功能,具体看代码:clas ...

  5. xxxxxxx

    int c; int b; bool h;

  6. 新浪ip地址转换接口

    通过IP地址获取对应的地区信息通常有两种方法:1)自己写程序,解析IP对应的地区信息,需要数据库.2)根据第三方提供的API查询获取地区信息. 第一种方法,参见文本<通过纯真IP数据库获取IP地 ...

  7. linux下c语言实现搜索根目录下所有文件(转-wangxiangshang)

    头文件: #include<dirent.h> #include<sys/types.h> opendir(): 函数原型: DIR * opendir(const char* ...

  8. reactjs

    摘自阮一峰博客:http://www.ruanyifeng.com/blog/2015/03/react.html 现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 Rea ...

  9. 05_整理String类的Length()、charAt()、 getChars()、replace()、 toUpperCase()、 toLowerCase()、trim()、toCharArray()使用说明

    Question: 整理String类的Length().charAt(). getChars().replace(). toUpperCase(). toLowerCase().trim().toC ...

  10. python基础篇

    python脚本开头 #!/usr/bin/env python# -*- coding: utf-8 -*print "你好,世界" 不要问为什么,记住就好了 变量定于的规则 变 ...