Task

Encode a string using an MD5 algorithm.   The algorithm can be found on   Wikipedia.



Optionally, validate your implementation by running all of the test values in   IETF RFC (1321)   for MD5.

Additionally,   RFC 1321   provides more precise information on the algorithm than the Wikipedia article.



 Warning:   MD5 has known weaknesses, including collisions and forged signatures.   Users may consider a stronger alternative when doing production-grade cryptography, such as SHA-256 (from the SHA-2 family), or the upcoming SHA-3.

If the solution on this page is a library solution, see   MD5/Implementation   for an implementation from scratch.




**FREE
Ctl-opt MAIN(Main);
Ctl-opt DFTACTGRP(*NO) ACTGRP(*NEW);
 
dcl-pr QDCXLATE EXTPGM('QDCXLATE');
  dataLen         packed(5 : 0) CONST;
  data            char(32767) options(*VARSIZE);
  conversionTable char(10) CONST;
end-pr;
 
dcl-pr Qc3CalculateHash EXTPROC('Qc3CalculateHash');
  inputData             pointer value;
  inputDataLen          int(10) const;
  inputDataFormat       char(8) const;
  algorithmDscr         char(16) const;
  algorithmFormat       char(8) const;
  cryptoServiceProvider char(1) const;
  cryptoDeviceName      char(1) const options(*OMIT);
  hash                  char(64) options(*VARSIZE : *OMIT);
  errorCode             char(32767) options(*VARSIZE);
end-pr;
 
dcl-c HEX_CHARS CONST('0123456789ABCDEF');
 
dcl-proc Main;
  dcl-s inputData char(45);
  dcl-s inputDataLen int(10) INZ(0);
  dcl-s outputHash char(16);
  dcl-s outputHashHex char(32);
  dcl-ds algorithmDscr QUALIFIED;
    hashAlgorithm int(10) INZ(0);
  end-ds;
  dcl-ds ERRC0100_NULL QUALIFIED;
    bytesProvided int(10) INZ(0);  // Leave at zero
    bytesAvailable int(10);
  end-ds;
 
  dow inputDataLen = 0;
    DSPLY 'Input: ' '' inputData;
    inputData = %trim(inputData);
    inputDataLen = %len(%trim(inputData));
    DSPLY ('Input=' + inputData);
    DSPLY ('InputLen=' + %char(inputDataLen));
    if inputDataLen = 0;
      DSPLY 'Input must not be blank';
    endif;
  enddo;
 
  // Convert from EBCDIC to ASCII
  QDCXLATE(inputDataLen : inputData : 'QTCPASC');
  algorithmDscr.hashAlgorithm = 1;   // MD5
  // Calculate hash
  Qc3CalculateHash(%addr(inputData) : inputDataLen : 'DATA0100' : algorithmDscr
                   : 'ALGD0500' : '0' : *OMIT : outputHash : ERRC0100_NULL);
  // Convert to hex
  CVTHC(outputHashHex : outputHash : 32);
  DSPLY ('MD5: ' + outputHashHex);
  return;
end-proc;
 
// This procedure is actually a MI, but I couldn't get it to bind so I wrote my own version
dcl-proc CVTHC;
  dcl-pi *N;
    target char(65534) options(*VARSIZE);
    srcBits char(32767) options(*VARSIZE) CONST;
    targetLen int(10) value;
  end-pi;
  dcl-s i int(10);
  dcl-s lowNibble ind INZ(*OFF);
  dcl-s inputOffset int(10) INZ(1);
  dcl-ds dataStruct QUALIFIED;
    numField int(5) INZ(0);
    // IBM i is big-endian
    charField char(1) OVERLAY(numField : 2);
  end-ds;
 
  for i = 1 to targetLen;
    if lowNibble;
      dataStruct.charField = %BitAnd(%subst(srcBits : inputOffset : 1) : X'0F');
      inputOffset += 1;
    else;
      dataStruct.charField = %BitAnd(%subst(srcBits : inputOffset : 1) : X'F0');
      dataStruct.numField /= 16;
    endif;
    %subst(target : i : 1) = %subst(HEX_CHARS : dataStruct.numField + 1 : 1);
    lowNibble = NOT lowNibble;
  endfor;
  return;
end-proc;