• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

使用delphi+intraweb进行微信开发4—微信消息加解密使用delphi+intraweb进行微信开发1 ...

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

示例代码已经放出!请移步进行下载,虽为示例代码但是是从我项目中移出来的,封装很完备适于自行扩展和修改。

 

上一讲当中我做了个简单的微信文本消息回显应用,当时是以微信明文方式实现的,其实微信推荐的是消息应该加密传输以增加安全性,所以这讲说说微信消息的加解密。

在微信的帮助页面上可以下载微信消息加解密的例程,可惜的是没有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


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
MATLAB绘图发布时间:2022-07-18
下一篇:
使用 matlab 深度学习工具训练模型发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap