示例程式碼已經放出!請移步使用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.

呵呵,看看效果圖吧: