Thema: Delphi DEC und HMAC-SHA-256

Einzelnen Beitrag anzeigen

Benutzerbild von Codewalker
Codewalker

Registriert seit: 18. Nov 2005
Ort: Ratingen
945 Beiträge
 
Delphi XE2 Professional
 
#3

Re: DEC und HMAC-SHA-256

  Alt 19. Apr 2010, 12:08
Ganz so einfach ist es leider nicht. Das bitweise xor lässt sich nicht einfach auf Strings anwenden, das Padding muss man noch selbst implementieren (soweit bin ich hoffentlich) - Problem ist, dass ich keine Beispiele für gültige Ein-/Ausgaben gefunden habe, um zu testen, ob es denn überhaupt richtig ist.

Für alle die es ausprobieren oder mit basteln wollen, hier mal der gesamte Quelltext. Aufgerufen wird Button1Click(). Es geht um die Produktdatenbankabfrage bei Amazon, man muss sich dort kostenlos registrieren, um einen Schlüssel zu bekommen. Außerdem nutze ich das DEC und himXML.
Delphi-Quellcode:
unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, InvokeRegistry, Rio, SOAPHTTPClient, AWSECommerceService, StdCtrls,
  himXML, DECUtil, DECCipher, DECHash, DECFmt;

const
  AWSID = 'DIE_ID';
  sAWSID = 'Die geheime ID';
  sACCES_ID = 'Den Associate-Tag';

type
  TForm1 = class(TForm)
    HTTPRIO1: THTTPRIO;
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure HTTPRIO1BeforeExecute(const MethodName: string;
      SOAPRequest: TStream);
  private
    function GenerateCurrentTimeStamp: string;
    function GenerateHMACSignature(Action, Timestamp: string): String;
    function concat(c: Char; l: Integer): String;
    function SimpleCryptString(const S, Key: string): string;
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
 AWSPort: AWSECommerceServicePortType;
  AmazonPort: AWSECommerceServicePortType;
  body: ItemSearch;
  arr_request: Array_Of_ItemSearchRequest;
  aRequest: ItemSearchRequest;
  aResponse: ItemSearchResponse;
  i: Integer;
  j: Integer;
begin
 AWSPort := GetAWSECommerceServicePortType(False,'',HTTPRIO1);
   body := ItemSearch.Create;
   body.AWSAccessKeyId := AWSID;
   body.SubscriptionId := sACCES_ID;
   body.AssociateTag := sACCES_ID;

    aRequest := ItemSearchrequest.Create;
    aRequest.SearchIndex := 'Video';
    aRequest.Title := 'Matrix';

    SetLength(arr_request, 1);
    arr_request[0] := aRequest;
    body.Request := arr_request;

    aResponse := AWSPort.ItemSearch(body);
    for i := 0 to Length(aResponse.Items) - 1 do
      for j := 0 to Length(aResponse.Items[i].Item) - 1 do
      begin
        Memo1.Lines.Add(aResponse.Items[i].Item[j].ItemAttributes.Title);
      end;
end;

function TForm1.GenerateCurrentTimeStamp(): string;
var
 TimeStamp: string;
 y,mon,d,h,m,s,ms: Word;
begin
 DecodeDate(Now,y,mon,d);
 DecodeTime(Now,h,m,s,ms);
// 2009-02-16T17:39:51.000Z
 Result := Format('%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.000Z',[y,mon,d,h,m,s]);
end;

function TForm1.concat(c: Char; l: Integer): String;
var
  I: Integer;
begin
 Result := '';
 for I := 0 to l-1 do
   Result := '0' + Result;
end;

function TForm1.SimpleCryptString(const S, Key: string): string;
var
  i, j: Integer;
  C: Byte;
  P: PByte;
begin
  SetLength(Result, Length(S));
  P := PByte(Result);

  j := 1;
  for i := 1 to Length(S) do
  begin
    C := Ord(S[i]);

    C := C xor Ord(Key[j]);
    P^ := C;
    Inc(P);
    Inc(j);
    if j > Length(Key) then
      j := 1;
  end;
end;

function TForm1.GenerateHMACSignature(Action: String; Timestamp: string): String;
var
 StringToSign: string;
 SignedString: string;
 CodedSignedString: string;
 key, amessage: string;
 blocksize: Integer;
 opad, ipad: String;
 i: Integer;
var
  AHashClass: TDECHashClass;
  ATextFormat: TDECFormatClass;
begin
 blocksize := 512;
 AHashClass := THash_SHA256;
 ATextFormat := TFormat_MIME64;
 key := sAWSID;

 StringToSign := Action + Timestamp;

if (length(key) > blocksize) then
        key := AHashClass.CalcBinary(key) // keys longer than blocksize are shortened
    else if (length(key) < blocksize) then
        key := key + concat('0',blocksize - length(key)); // keys shorter than blocksize are zero-padded

    opad := concat(Chr(92),blocksize); // Where blocksize is that of the underlying hash function
    ipad := concat(Chr(54),blocksize); // Where xor is exclusive or (XOR)
    opad := SimpleCryptString(opad,key);
    ipad := SimpleCryptString(ipad,key);
// for I := 1 to Length(opad) do begin
// opad[i] := opad[i] xor key;
// ipad[i] := ipad[i] xor key;
// end;

    SignedString := AHashClass.CalcBinary(opad + AHashClass.CalcBinary(ipad + amessage)); // Where + is concatenation
    Result := SignedString;
end;

procedure TForm1.HTTPRIO1BeforeExecute(const MethodName: string;
  SOAPRequest: TStream);
var
 XML: TXMLFile;
 Node: TXMLNode;
 S: string;
begin
 SOAPRequest.Seek(0,0);

 XML := TXMLFile.Create(Self,false);
 xml.LoadFromStream(SOAPRequest);
 Node := XML.RootNode.Node['SOAP-ENV:Body'].Node['ItemSearch'];
 Node.AddNode('Timestamp').Text := GenerateCurrentTimeStamp;
 Node.AddNode('Action').Text := 'ItemSearch';
 Node.AddNode('Signature').Text_Base64w := GenerateHMACSignature('ItemSearch',Node.Node['Timestamp'].Text);
 SOAPRequest.Seek(0,0);
 xml.SaveToStream(SOAPRequest);
 xml.SaveToXML(S);
 Memo1.Text := S;
end;

end.
Bin für jede Hilfe dankbar.
  Mit Zitat antworten Zitat