AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

DEC und HMAC-SHA-256

Offene Frage von "Codewalker"
Ein Thema von Codewalker · begonnen am 19. Apr 2010 · letzter Beitrag vom 4. Mai 2010
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von Codewalker
Codewalker

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

DEC und HMAC-SHA-256

  Alt 19. Apr 2010, 10:11
Hallo zusammen.

Ich bin auf der Suche nach einer Implementierung des HMAC-SHA-256 Link zu Wikipedia. Im der Readme des DEC steht aber nur SHA-256 und das ist wohl nicht das gleiche. Kennt jemand eine Implementierung des HMAC-SHA-256 (oder falls Hagen das liest: Kommt sowas noch ins DEC?)

Grüße
  Mit Zitat antworten Zitat
Andreas L.
(Gast)

n/a Beiträge
 
#2

Re: DEC und HMAC-SHA-256

  Alt 19. Apr 2010, 12:01
In den Wikipedia-Artikel ist ein super (sogar Pascal ähnlicher) Pseudocode:
Delphi-Quellcode:
function hmac (key, message)
    if (length(key) > blocksize) then
        key = hash(key) // keys longer than blocksize are shortened
    else if (length(key) < blocksize) then
        key = key ∥ zeroes(blocksize - length(key)) // keys shorter than blocksize are zero-padded
    end if
    
    opad = [0x5c * blocksize] ⊕ key // Where blocksize is that of the underlying hash function
    ipad = [0x36 * blocksize] ⊕ key // Where ⊕ is exclusive or (XOR)
    
    return hash(opad ∥ hash(ipad ∥ message)) // Where ∥ is concatenation
end function
Da brauchst nicht viel ändern. Anstatt der Funktion Hash verwendest einfach SHA256 aus dem DEC.
  Mit Zitat antworten Zitat
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
gammatester

Registriert seit: 6. Dez 2005
999 Beiträge
 
#4

Re: DEC und HMAC-SHA-256

  Alt 19. Apr 2010, 18:47
Der Pseudocode ist wirklich grausam (ein Operatorzeichen für mehrere verschieden Operation etc).

Aber auch in Deinem Code sind aber noch einige Bugs drin:

- Concat verwendet überhaupt nicht das übergebene c:char
- padding muß mit #0 und nich '0' erfolgen

Vollständig getesteten HMAC-Quellcode findest und mit den Testvektoren (und Referenzen) auf meiner CRC-Hash-Seite CRC-Hash-Seite
im Archive crc_hash_2010-03-26.zip, und eine kurze Einführung auf kurze Einführung

Allerdings sind die Funktionen auf's wesentlich beschränkt (Base64 für Amazon mußt Du zB selbst ausführen), allerdings haben schon etliche Leute die Routinen für Amazon verwendet.
  Mit Zitat antworten Zitat
Benutzerbild von Codewalker
Codewalker

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

Re: DEC und HMAC-SHA-256

  Alt 19. Apr 2010, 20:17
Okay, der Code war zusammengeschustert ... und das sieht man. Ich habs mal auf das Wesentliche reduziert.
Delphi-Quellcode:

uses HMAC, Hash, SHA256, mem_util;

{...}

function GenerateHMACSignature(Text: string; Key: string): string;
var
  ctx: THMAC_Context;
  phash: PHashDesc;
  mac: THashDigest;
begin
  phash := FindHash_by_Name('SHA256');
  if phash = nil then
  begin
    {Action for 'Hash function not found/registered.'}
    exit;
  end;
  hmac_init(ctx, phash, @key, sizeof(key));
  hmac_update(ctx, @Text, sizeof(Text));
  hmac_final(ctx, mac);
  Result := HexStr(@mac, Length(mac));
end;
Bin mir trotz Doku nicht sicher, ob das so richtig ist, da ich die Test Vectors des zugehörigen RFCs und auch einige Beispiele von Webgeneratoren nicht reproduzieren konnte. Kennt sich jemand mit diesen Units aus und kann mir sagen wo mein Fehler ist?

Außerdem ist mir immer noch nicht klar, WOVON genau Amazon möchte, dass ich die Signatur erstelle. Laut deren Doku soll es ein TimeStamp sein (s.o. im Quelltext. Das sollte gehen) und der Inhalt des Action-Tags - nur leider enthält der vom WSDL erzeugte Envelope überhaupt kein solches Tag.
Es ist echt ein Krampf, die Schnittstelle war mal so gut
  Mit Zitat antworten Zitat
Klaus01
Online

Registriert seit: 30. Nov 2005
Ort: München
5.755 Beiträge
 
Delphi 10.4 Sydney
 
#6

Re: DEC und HMAC-SHA-256

  Alt 19. Apr 2010, 20:32
Guten Abend,

könnte es hier eine Rolle spielen das String = UniCode ist,
und die Beispiele auf AnsiString basieren?

Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
gammatester

Registriert seit: 6. Dez 2005
999 Beiträge
 
#7

Re: DEC und HMAC-SHA-256

  Alt 19. Apr 2010, 21:07
Warum benutzen hier eigentlich die meisten immer diese unsäglichen Strings, Hash und HMAC arbeitet mit Bit/Bytefolgen. Wenn schon Strings dann richtig: daß erste Zeichen ist key[1], Länge nicht sizeof(=4!) sondern length. Bei meinen Supportanfragen mußten auch immer ansistrings für Amazon benutzt werden.

Hier die korrigierte Funktion:
Delphi-Quellcode:
function GenerateHMACSignature(Text, key: ansistring): ansistring;
var
  ctx: THMAC_Context;
  phash: PHashDesc;
  mac: THashDigest;
begin
  phash := FindHash_by_Name('SHA256');
  if phash = nil then
  begin
    {Action for 'Hash function not found/registered.'}
    exit;
  end;
  hmac_init(ctx, phash, @key[1], length(key));
  hmac_update(ctx, @Text[1], length(Text));
  hmac_final(ctx, mac);
  Result := HexStr(@mac, sizeof(mac));
end;
  Mit Zitat antworten Zitat
Benutzerbild von Codewalker
Codewalker

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

Re: DEC und HMAC-SHA-256

  Alt 30. Apr 2010, 10:30
Also, ich habe das ganze aus einem funktionierenden PHP-Skript übernommen und versucht das ganze in Delphi umzusetzen. Das PHP-Skript ist wie folgt:
Code:
<?php
   session_start();
   $t = $_REQUEST["t"];
   $k = $_REQUEST["k"];
   if ((empty($t)) || (empty($k)))
   {
      die;
   }

$aktuelle        = gmdate("Y-m-d\TH:i:s\Z");
$aktuellezeit   = urlencode($aktuelle);

$signature1 = hash_hmac("sha256", $t, $k, true);
$signature2  = base64_encode($signature1);
      
print "Timestamp: \t $aktuelle
";
print "Timestamp (URLEnccode): \t $aktuellezeit
";
print "Text: \t $t
";
print "Key: \t $k
";
print "Result: \t $signature1 
";
print "Result_Base64: \t $signature2";
?>
Damit kann ich mir eine erfolgreiche HMAC-Verschlüsselung aus PHP ausgeben lassen. Jetzt versuche ich das ganze mit Wolfgangs CRC/Hash-Units in Delphi 2009 umzusetzen (siehe Anhang). Problem: Die Ergebnisse stimmen nicht überein. Ich hoffe jemand kann mir sagen, wo mein Fehler ist. Der Klartext ist "Test" und der Schlüssel ist "geheim". PHP liefert "eAGKtiF4J8GZY4TelvKwbxNTTMxeUjKfYYaPae6vIiQ=" , Delphi aber andere Werte.
Angehängte Dateien
Dateityp: zip hmactest_154.zip (7,5 KB, 48x aufgerufen)
Dateityp: exe hmactest_857.exe (556,5 KB, 36x aufgerufen)
  Mit Zitat antworten Zitat
gammatester

Registriert seit: 6. Dez 2005
999 Beiträge
 
#9

Re: DEC und HMAC-SHA-256

  Alt 30. Apr 2010, 11:37
Also zumindest ist die HMAC-Berechnung OK und das Ergebnis in Hex für 'Test' und 'geheim' ist 'b2f53072cc320d47e80cfd6a4e5faf3001c83bb3784c6da6d 8a8dded1978cfcc'. Dies stimmt (bis auf UpperCase) mit der Ausgabe von zB CryptoBench (basiert auf Crypto ++) überein.

Lass Dir mal das PHP-Ergebnis in Hex ausgeben. Was liefert denn PHP für die RFC-Testwerte, die Du zB in den Programmen t_hmac.pas und t_hmac2.pas findest?
  Mit Zitat antworten Zitat
Benutzerbild von Codewalker
Codewalker

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

Re: DEC und HMAC-SHA-256

  Alt 30. Apr 2010, 12:20
Wenn ich mich nicht vertan habe, dann bekomme ich als Ergebnis das folgende:
Code:
Timestamp: 2010-04-30T11:19:35Z
Timestamp (URLEnccode): 2010-04-30T11%3A19%3A35Z
Text: "Test"
Key: "geheim"
Result: xŠ¶!x'Á™c„Þ–ò°oSLÌ^R2Ÿa†iî¯"$
Result_Base64: eAGKtiF4J8GZY4TelvKwbxNTTMxeUjKfYYaPae6vIiQ=
Result_Hex: 7818ab6217827c1996384de96f2b06f13534ccc5e52329f61868f69eeaf2224
Die Konvertierung lief wie folgt:
Code:
    for ($i=0; $i < strlen($hex); $i++)
    {
        $s .= dechex(ord($hex[$i]));
    }
Die Testvektoren werde ich später mal durchprobieren
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:06 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz