[ABAP] Message Authentication Code (MAC) mit verschiedenen HASH-Algorithmen (MD5, SHA1, SHA256, SHA384, SHA512) berechnen

Variante 1 (Strings)

* MD5, SHA1, SHA256, SHA384, SHA512
DATA(lv_algo) = |SHA256|.
* Key
DATA(lv_key) = |MyKey1|.
* Key als XSTRING
DATA(lv_keyx) = cl_abap_hmac=>string_to_xstring( lv_key ).
* zu kodierende String-Daten
DATA(lv_data) = |Teststring|.

* HMAC-Wert als Hex-Encoded String
DATA: lv_hmacstring TYPE string.
* HMAC-Wert binär als XString
DATA: lv_hmacxstring TYPE xstring.
* HMAC-Wert als Base64-Encoded String
DATA: lv_hmacb64string TYPE string.

TRY.
* Generische HMAC-Funktion (Char-Input)
    cl_abap_hmac=>calculate_hmac_for_char( EXPORTING
                                             if_algorithm     = lv_algo
                                             if_key           = lv_keyx
                                             if_data          = lv_data
                                           IMPORTING
                                             ef_hmacstring    = lv_hmacstring
                                             ef_hmacxstring   = lv_hmacxstring
                                             ef_hmacb64string = lv_hmacb64string ).
    cl_demo_output=>write_data( lv_algo ).
    cl_demo_output=>write_data( lv_key ).
    cl_demo_output=>write_data( lv_keyx ).
    cl_demo_output=>write_data( lv_data ).
    cl_demo_output=>write_data( lv_hmacstring ).
    cl_demo_output=>write_data( lv_hmacxstring ).
    cl_demo_output=>write_data( lv_hmacb64string ).
    cl_demo_output=>display( ).
  CATCH cx_root INTO DATA(e_txt).
    WRITE: / e_txt->get_text( ).
ENDTRY.

Variante 2 (Bytefolgen / RAW)

* MD5, SHA1, SHA256, SHA384, SHA512
DATA(lv_algo) = |SHA256|.
* Key
DATA(lv_key) = |MyKey1|.
* Key als XSTRING
DATA(lv_keyx) = cl_abap_hmac=>string_to_xstring( lv_key ).
* zu kodierende String-Daten
DATA(lv_data) = |Teststring|.
* zu kodierende String-Daten als XSTRING
DATA(lv_datax) = cl_abap_message_digest=>string_to_xstring( lv_data ).

* HMAC-Wert als Hex-Encoded String
DATA: lv_hmacstring TYPE string.
* HMAC-Wert binär als XString
DATA: lv_hmacxstring TYPE xstring.
* HMAC-Wert als Base64-Encoded String
DATA: lv_hmacb64string TYPE string.

TRY.
* Generische HMAC-Funktion (XString)
    cl_abap_hmac=>calculate_hmac_for_raw( EXPORTING
                                            if_algorithm     = lv_algo
                                            if_key           = lv_keyx
                                            if_data          = lv_datax
                                          IMPORTING
                                            ef_hmacstring    = lv_hmacstring
                                            ef_hmacxstring   = lv_hmacxstring
                                            ef_hmacb64string = lv_hmacb64string ).
    cl_demo_output=>write_data( lv_algo ).
    cl_demo_output=>write_data( lv_key ).
    cl_demo_output=>write_data( lv_keyx ).
    cl_demo_output=>write_data( lv_data ).
    cl_demo_output=>write_data( lv_datax ).
    cl_demo_output=>write_data( lv_hmacstring ).
    cl_demo_output=>write_data( lv_hmacxstring ).
    cl_demo_output=>write_data( lv_hmacb64string ).
    cl_demo_output=>display( ).
  CATCH cx_root INTO DATA(e_txt).
    WRITE: / e_txt->get_text( ).
ENDTRY.

MD5

  • Der folgende Quellcode ist eine BCB-Abwandlung des MD5 Message Digest Algorithm zum Codieren von Strings mittels MD5 Checksummen.
  • Verwendung:
#include "md5.h";

...

MD5Obj *pMD5 = new MD5Obj();

// MD5-Hash eines Strings
AnsiString sInput = "abc"; //MD5 Hash: 900150983cd24fb0d6963f7d28e17f72
AnsiString sTest = pMD5->MD5_CheckString(sInput);

// MD5-Hash einer Datei
int iFileSize;
int iFileHandle;
int iBytesRead;
char *pchTemp;
AnsiString sMD5Str = "";

iFileHandle = FileOpen(sInput.c_str(), fmShareDenyWrite);

if (iFileHandle)
{
  iFileSize = FileSeek(iFileHandle, 0, 2);
  FileSeek(iFileHandle, 0, 0);

  pchTemp = new char[iFileSize+1];

  iBytesRead = FileRead(iFileHandle, pchTemp, iFileSize);

  if (iBytesRead == iFileSize) sMD5Str = pMD5->MD5_CheckFile(pchTemp, iFileSize);

  delete[] pchTemp;

  FileClose(iFileHandle);
}

if (pMD5) delete pMD5;
  • md5.h
#ifndef MD5_H
#define MD5_H
#ifdef __alpha
typedef unsigned int uint32;
#else
typedef unsigned long uint32;
#endif

#include <vcl.h>

struct MD5Context
{
    uint32 buf[4];
    uint32 bits[2];
    unsigned char in[64];
};

class MD5Obj
{
    public:

    MD5Obj(){};
    void MD5Init(struct MD5Context *ctx);
    void MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len);
    void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
    void MD5Transform(uint32 buf[4], uint32 in[16]);
    AnsiString MD5_CheckString(AnsiString sInputString);
    AnsiString MD5_CheckFile(char *cpFileData, int iLength);
};

typedef struct MD5Context MD5_CTX;

#endif
  • md5.cpp
// A Borland C++ implementation of the RSA Data Security, Inc. MD5 Message Digest Algorithm, as defined in RFC 1321.

#include "stdio.h"
#include <string.h>
#include "md5.h"
#ifdef sgi
#define HIGHFIRST
#endif

#ifdef sun
#define HIGHFIRST
#endif

#ifndef HIGHFIRST 
#define byteReverse(buf, len)
#else

void byteReverse(unsigned char *buf, unsigned longs)
{
    uint32 t;

    do
    {
        t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]);

        *(uint32 *) buf = t;
        buf += 4;

    } while (--longs);
}

#endif

#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))

#define MD5STEP(f, w, x, y, z, data, s) ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
//---------------------------------------------------------------------------
void MD5Obj::MD5Init(struct MD5Context *ctx)
{
    ctx->buf[0] = 0x67452301;
    ctx->buf[1] = 0xefcdab89;
    ctx->buf[2] = 0x98badcfe;
    ctx->buf[3] = 0x10325476;
    ctx->bits[0] = 0;
    ctx->bits[1] = 0;
}
//---------------------------------------------------------------------------
void MD5Obj::MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len)
{
    uint32 t;
    t = ctx->bits[0];

    if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) ctx->bits[1]++;

    ctx->bits[1] += len >> 29;
    t = (t >> 3) & 0x3f;

    if (t)
    {
        unsigned char *p = (unsigned char *) ctx->in + t;
        t = 64 - t;

        if (len < t)
        {
            memcpy(p, buf, len);
            return;
        }

        memcpy(p, buf, t);
        byteReverse(ctx->in, 16);

        MD5Transform(ctx->buf,(uint32*)ctx->in);

        buf += t;
        len -= t;
    }

    while (len >= 64)
    {
        memcpy(ctx->in, buf, 64);
        byteReverse(ctx->in, 16);

        MD5Transform(ctx->buf, (uint32 *) ctx->in);

        buf += 64;

        len -= 64;
    }

    memcpy(ctx->in, buf, len);
}
//---------------------------------------------------------------------------
void MD5Obj::MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
    unsigned count;
    unsigned char *p;

    count = (ctx->bits[0] >> 3) & 0x3F;
    p = ctx->in + count;
    *p++ = 0x80;
    count = 64 - 1 - count;

    if (count < 8)
    {
        memset(p, 0, count);
        byteReverse(ctx->in, 16);

        MD5Transform(ctx->buf, (uint32 *) ctx->in);

        memset(ctx->in, 0, 56);
    }
    else
    {
        memset(p, 0, count - 8);
    }

    byteReverse(ctx->in, 14);

    ((uint32 *) ctx->in)[14] = ctx->bits[0];
    ((uint32 *) ctx->in)[15] = ctx->bits[1];


    MD5Transform(ctx->buf,(uint32 *) ctx->in);

    byteReverse((unsigned char *) ctx->buf, 4);

    memcpy(digest, ctx->buf, 16);
    memset(ctx, 0, sizeof(ctx));
}
//---------------------------------------------------------------------------
void MD5Obj::MD5Transform(uint32 buf[4], uint32 in[16])
{
    register uint32 a, b, c, d;
    a = buf[0];
    b = buf[1];
    c = buf[2];
    d = buf[3];

    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);

    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); 
    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); 
    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); 
    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); 
    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); 
    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); 
    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); 
    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); 
    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); 
    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); 
    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); 
    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); 
    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); 
    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); 

    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); 
    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); 
    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); 
    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); 
    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); 
    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); 
    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); 
    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); 
    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); 
    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); 
    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); 
    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); 
    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); 
    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); 
    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); 
    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); 

    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); 
    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); 
    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); 
    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); 
    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); 
    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); 
    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); 
    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); 
    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); 
    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); 
    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); 
    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); 
    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); 
    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); 
    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); 
    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); 

    buf[0] += a; 
    buf[1] += b; 
    buf[2] += c; 
    buf[3] += d;
}
//--------------------------------------------------------------------------- 
AnsiString MD5Obj::MD5_CheckString(AnsiString sInputString)
{
    struct MD5Context ctx;
    char *password = sInputString.c_str();
    unsigned char digest[16];

    MD5Init (&ctx);
    MD5Update (&ctx, password, strlen(password));
    MD5Final (digest, &ctx);
    char tmp[33];

    for (int s=0; s<16; s++) sprintf (&tmp[s+s], "%02x", digest[s]);

    AnsiString sRetStr = tmp;

    return sRetStr;
}
//---------------------------------------------------------------------------
AnsiString MD5Obj::MD5_CheckFile(char *cpFileData, int iLength)
{
    struct MD5Context ctx;
    unsigned char digest[16];

    MD5Init (&ctx);
    MD5Update (&ctx, cpFileData, iLength);
    MD5Final (digest, &ctx);
    char tmp[33];

    for (int s=0; s<16; s++) sprintf (&tmp[s+s], "%02x", digest[s]);

    AnsiString sRetStr = tmp;

    return sRetStr;
}