"Fossies" - the Fresh Open Source Software Archive

Member "seed7/lib/msgdigest.s7i" (19 Mar 2020, 43695 Bytes) of package /linux/misc/seed7_05_20210223.tgz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 
    2 (********************************************************************)
    3 (*                                                                  *)
    4 (*  msgdigest.s7i  Message digest and secure hash algorithms.       *)
    5 (*  Copyright (C) 2013, 2014, 2017 - 2019  Thomas Mertes            *)
    6 (*                                                                  *)
    7 (*  This file is part of the Seed7 Runtime Library.                 *)
    8 (*                                                                  *)
    9 (*  The Seed7 Runtime Library is free software; you can             *)
   10 (*  redistribute it and/or modify it under the terms of the GNU     *)
   11 (*  Lesser General Public License as published by the Free Software *)
   12 (*  Foundation; either version 2.1 of the License, or (at your      *)
   13 (*  option) any later version.                                      *)
   14 (*                                                                  *)
   15 (*  The Seed7 Runtime Library is distributed in the hope that it    *)
   16 (*  will be useful, but WITHOUT ANY WARRANTY; without even the      *)
   17 (*  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
   18 (*  PURPOSE.  See the GNU Lesser General Public License for more    *)
   19 (*  details.                                                        *)
   20 (*                                                                  *)
   21 (*  You should have received a copy of the GNU Lesser General       *)
   22 (*  Public License along with this program; if not, write to the    *)
   23 (*  Free Software Foundation, Inc., 51 Franklin Street,             *)
   24 (*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
   25 (*                                                                  *)
   26 (********************************************************************)
   27 
   28 
   29 include "bytedata.s7i";
   30 include "bin32.s7i";
   31 include "bin64.s7i";
   32 include "float.s7i";
   33 include "math.s7i";
   34 
   35 
   36 (**
   37  *  Compute a message digest with the MD4 message digest algorithm.
   38  *  The security of MD4 has been severely compromised. This function
   39  *  is provided for backward compatibility.
   40  *  @return the MD4 message digest (a string of 16 bytes).
   41  *  @exception RANGE_ERROR If ''message'' contains a character beyond '\255;'.
   42  *)
   43 const func string: md4 (in var string: message) is func
   44   result
   45     var string: digest is "";
   46   local
   47     # Specify the per-round shift amounts
   48     const array integer: shiftAmount is [] (
   49         3,  7, 11, 19,  3,  7, 11, 19,  3,  7, 11, 19,  3,  7, 11, 19,
   50         3,  5,  9, 13,  3,  5,  9, 13,  3,  5,  9, 13,  3,  5,  9, 13,
   51         3,  9, 11, 15,  3,  9, 11, 15,  3,  9, 11, 15,  3,  9, 11, 15);
   52     const array integer: idx is [] (
   53         1,  9,  5, 13,  3, 11,  7, 15,  2, 10,  6, 14,  4, 12,  8, 16);
   54     var integer: length is 0;
   55     var integer: wordIndex is 1;
   56     var integer: index is 0;
   57     var array bin32: m is 16 times bin32.value;
   58     var integer: a0 is 16#67452301;   # a
   59     var integer: b0 is 16#efcdab89;   # b
   60     var integer: c0 is 16#98badcfe;   # c
   61     var integer: d0 is 16#10325476;   # d
   62     var bin32: a is bin32(0);
   63     var bin32: b is bin32(0);
   64     var bin32: c is bin32(0);
   65     var bin32: d is bin32(0);
   66     var bin32: f is bin32(0);
   67     var integer: g is 0;
   68     var bin32: temp is bin32(0);
   69   begin
   70     length := length(message);
   71     # Append the bit '1' to the message.
   72     message &:= '\16#80;';
   73     # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
   74     message &:= "\0;" mult 63 - (length + 8) mod 64;
   75     # Append length of message (before pre-processing), in bits, as 64-bit little-endian integer.
   76     message &:= int64AsEightBytesLe(8 * length);
   77 
   78     # Process the message in successive 512-bit chunks:
   79     while wordIndex <= length(message) do
   80       # Break chunk into sixteen 32-bit little-endian words.
   81       for index range 1 to 16 do
   82         m[index] := bin32(bytes2Int(message[wordIndex len 4], UNSIGNED, LE));
   83         wordIndex +:= 4;
   84       end for;
   85 
   86       a := bin32(a0 mod 16#100000000);
   87       b := bin32(b0 mod 16#100000000);
   88       c := bin32(c0 mod 16#100000000);
   89       d := bin32(d0 mod 16#100000000);
   90 
   91       for index range 1 to 48 do
   92         if index <= 16 then
   93           f := d >< (b & (c >< d));
   94           g := index;
   95         elsif index <= 32 then
   96           f := bin32(ord(b & (c | d) | (c & d)) + 16#5a827999);
   97           g := (4 * index + 7) mod 15 + (index mdiv 32) * 15 + 1;
   98         else
   99           f := bin32(ord(b >< c >< d) + 16#6ed9eba1);
  100           g := idx[index - 32];
  101         end if;
  102         temp := d;
  103         d := c;
  104         c := b;
  105         b := rotLeft(bin32((ord(a) + ord(f) + ord(m[g])) mod 16#100000000),
  106                      shiftAmount[index]);
  107         a := temp;
  108       end for;
  109 
  110       # Add this chunk's hash to result so far:
  111       a0 +:= ord(a);
  112       b0 +:= ord(b);
  113       c0 +:= ord(c);
  114       d0 +:= ord(d);
  115     end while;
  116 
  117     # Produce the final hash value:
  118     digest := int32AsFourBytesLe(a0) &
  119               int32AsFourBytesLe(b0) &
  120               int32AsFourBytesLe(c0) &
  121               int32AsFourBytesLe(d0);
  122   end func;
  123 
  124 
  125 # Use binary integer part of the sines of integers (Radians) as constants:
  126 const func array integer: createMd5Table is func
  127   result
  128     var array integer: k is 64 times 0;
  129   local
  130     var integer: index is 0;
  131   begin
  132     for index range 1 to 64 do
  133       k[index] := trunc(abs(sin(flt(index))) * 2.0 ** 32);
  134     end for;
  135   end func;
  136 
  137 
  138 (**
  139  *  Compute a message digest with the MD5 message digest algorithm.
  140  *  MD5 is considered to be cryptographically broken. This function
  141  *  is provided for backward compatibility.
  142  *  @return the MD5 message digest (a string of 16 bytes).
  143  *  @exception RANGE_ERROR If ''message'' contains a character beyond '\255;'.
  144  *)
  145 const func string: md5 (in var string: message) is func
  146   result
  147     var string: digest is "";
  148   local
  149     # Specify the per-round shift amounts
  150     const array integer: shiftAmount is [] (
  151         7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,
  152         5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,
  153         4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,
  154         6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21);
  155     const array integer: k is createMd5Table;
  156     var integer: length is 0;
  157     var integer: wordIndex is 1;
  158     var integer: index is 0;
  159     var array bin32: m is 16 times bin32.value;
  160     var integer: a0 is 16#67452301;   # a
  161     var integer: b0 is 16#efcdab89;   # b
  162     var integer: c0 is 16#98badcfe;   # c
  163     var integer: d0 is 16#10325476;   # d
  164     var bin32: a is bin32(0);
  165     var bin32: b is bin32(0);
  166     var bin32: c is bin32(0);
  167     var bin32: d is bin32(0);
  168     var bin32: f is bin32(0);
  169     var integer: g is 0;
  170     var bin32: temp is bin32(0);
  171   begin
  172     length := length(message);
  173     # Append the bit '1' to the message.
  174     message &:= '\16#80;';
  175     # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
  176     message &:= "\0;" mult 63 - (length + 8) mod 64;
  177     # Append length of message (before pre-processing), in bits, as 64-bit little-endian integer.
  178     message &:= int64AsEightBytesLe(8 * length);
  179 
  180     # Process the message in successive 512-bit chunks:
  181     while wordIndex <= length(message) do
  182       # Break chunk into sixteen 32-bit little-endian words.
  183       for index range 1 to 16 do
  184         m[index] := bin32(bytes2Int(message[wordIndex len 4], UNSIGNED, LE));
  185         wordIndex +:= 4;
  186       end for;
  187 
  188       a := bin32(a0 mod 16#100000000);
  189       b := bin32(b0 mod 16#100000000);
  190       c := bin32(c0 mod 16#100000000);
  191       d := bin32(d0 mod 16#100000000);
  192 
  193       for index range 1 to 64 do
  194         if index <= 16 then
  195           f := d >< (b & (c >< d));
  196           g := index;
  197         elsif index <= 32 then
  198           f := c >< (d & (b >< c));
  199           g := (5 * index - 4) mod 16 + 1;
  200         elsif index <= 48 then
  201           f := b >< c >< d;
  202           g := (3 * index + 2) mod 16 + 1;
  203         else
  204           f := c >< (b | (bin32(16#ffffffff) >< d));
  205           g := (7 * pred(index)) mod 16 + 1;
  206         end if;
  207 
  208         temp := d;
  209         d := c;
  210         c := b;
  211         b := bin32((ord(b) +
  212              ord(rotLeft(bin32((ord(a) + ord(f) + k[index] + ord(m[g])) mod 16#100000000),
  213                          shiftAmount[index]))) mod 16#100000000);
  214         a := temp;
  215       end for;
  216 
  217       # Add this chunk's hash to result so far:
  218       a0 +:= ord(a);
  219       b0 +:= ord(b);
  220       c0 +:= ord(c);
  221       d0 +:= ord(d);
  222     end while;
  223 
  224     # Produce the final hash value:
  225     digest := int32AsFourBytesLe(a0) &
  226               int32AsFourBytesLe(b0) &
  227               int32AsFourBytesLe(c0) &
  228               int32AsFourBytesLe(d0);
  229   end func;
  230 
  231 
  232 (**
  233  *  Compute a message digest with the RIPEMD-160 message digest algorithm.
  234  *  @return the RIPEMD-160 message digest (a string of 20 bytes).
  235  *  @exception RANGE_ERROR If ''message'' contains a character beyond '\255;'.
  236  *)
  237 const func string: ripemd160 (in var string: message) is func
  238   result
  239     var string: digest is "";
  240   local
  241     const array integer: k1 is [] (16#00000000, 16#5a827999, 16#6ed9eba1, 16#8f1bbcdc, 16#a953fd4e);
  242     const array integer: k2 is [] (16#50a28be6, 16#5c4dd124, 16#6d703ef3, 16#7a6d76e9, 16#00000000);
  243     const array integer: r1 is [] (
  244          1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
  245          8,  5, 14,  2, 11,  7, 16,  4, 13,  1, 10,  6,  3, 15, 12,  9,
  246          4, 11, 15,  5, 10, 16,  9,  2,  3,  8,  1,  7, 14, 12,  6, 13,
  247          2, 10, 12, 11,  1,  9, 13,  5, 14,  4,  8, 16, 15,  6,  7,  3,
  248          5,  1,  6, 10,  8, 13,  3, 11, 15,  2,  4,  9, 12,  7, 16, 14);
  249     const array integer: r2 is [] (
  250          6, 15,  8,  1, 10,  3, 12,  5, 14,  7, 16,  9,  2, 11,  4, 13,
  251          7, 12,  4,  8,  1, 14,  6, 11, 15, 16,  9, 13,  5, 10,  2,  3,
  252         16,  6,  2,  4,  8, 15,  7, 10, 12,  9, 13,  3, 11,  1,  5, 14,
  253          9,  7,  5,  2,  4, 12, 16,  1,  6, 13,  3, 14, 10,  8, 11, 15,
  254         13, 16, 11,  5,  2,  6,  9,  8,  7,  3, 14, 15,  1,  4, 10, 12);
  255     const array integer: s1 is [] (
  256         11, 14, 15, 12,  5,  8,  7,  9, 11, 13, 14, 15,  6,  7,  9,  8,
  257          7,  6,  8, 13, 11,  9,  7, 15,  7, 12, 15,  9, 11,  7, 13, 12,
  258         11, 13,  6,  7, 14,  9, 13, 15, 14,  8, 13,  6,  5, 12,  7,  5,
  259         11, 12, 14, 15, 14, 15,  9,  8,  9, 14,  5,  6,  8,  6,  5, 12,
  260          9, 15,  5, 11,  6,  8, 13, 12,  5, 12, 13, 14, 11,  8,  5,  6);
  261     const array integer: s2 is [] (
  262          8,  9,  9, 11, 13, 15, 15,  5,  7,  7,  8, 11, 14, 14, 12,  6,
  263          9, 13, 15,  7, 12,  8,  9, 11,  7,  7, 12,  7,  6, 15, 13, 11,
  264          9,  7, 15, 11,  8,  6,  6, 14, 12, 13,  5, 14, 13, 13,  7,  5,
  265         15,  5,  8, 11, 14, 14,  6, 14,  6,  9, 12,  9, 12,  5, 15,  8,
  266          8,  5, 12,  9, 12,  5, 14,  6,  8, 13,  6,  5, 15, 13, 11, 11);
  267     var integer: length is 0;
  268     var integer: wordIndex is 1;
  269     var integer: index is 0;
  270     var array integer: x is 16 times 0;
  271     var integer: h0 is 16#67452301;
  272     var integer: h1 is 16#efcdab89;
  273     var integer: h2 is 16#98badcfe;
  274     var integer: h3 is 16#10325476;
  275     var integer: h4 is 16#c3d2e1f0;
  276     var bin32: a1 is bin32(0);
  277     var bin32: b1 is bin32(0);
  278     var bin32: c1 is bin32(0);
  279     var bin32: d1 is bin32(0);
  280     var bin32: e1 is bin32(0);
  281     var bin32: a2 is bin32(0);
  282     var bin32: b2 is bin32(0);
  283     var bin32: c2 is bin32(0);
  284     var bin32: d2 is bin32(0);
  285     var bin32: e2 is bin32(0);
  286     var integer: t1 is 0;
  287     var integer: t2 is 0;
  288   begin
  289     length := length(message);
  290     # Append the bit '1' to the message.
  291     message &:= '\16#80;';
  292     # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
  293     message &:= "\0;" mult 63 - (length + 8) mod 64;
  294     # Append length of message (before pre-processing), in bits, as 64-bit little-endian integer.
  295     message &:= int64AsEightBytesLe(8 * length);
  296 
  297     # Process the message in successive 512-bit chunks:
  298     while wordIndex <= length(message) do
  299       # Break chunk into sixteen 32-bit little-endian words.
  300       for index range 1 to 16 do
  301         x[index] := bytes2Int(message[wordIndex len 4], UNSIGNED, LE);
  302         wordIndex +:= 4;
  303       end for;
  304 
  305       a1 := bin32(h0);
  306       b1 := bin32(h1);
  307       c1 := bin32(h2);
  308       d1 := bin32(h3);
  309       e1 := bin32(h4);
  310       a2 := bin32(h0);
  311       b2 := bin32(h1);
  312       c2 := bin32(h2);
  313       d2 := bin32(h3);
  314       e2 := bin32(h4);
  315 
  316       for index range 1 to 80 do
  317         case index of
  318           when {1 .. 16}:
  319             t1 := ord(b1 >< c1 >< d1);  # + k1[1];
  320             t2 := ord(b2 >< (c2 | ~d2)) + k2[1];
  321           when {17 .. 32}:
  322             t1 := ord((b1 & c1) | (~b1 & d1)) + k1[2];
  323             t2 := ord((b2 & d2) | (c2 & ~d2)) + k2[2];
  324           when {33 .. 48}:
  325             t1 := ord((b1 | ~c1) >< d1) + k1[3];
  326             t2 := ord((b2 | ~c2) >< d2) + k2[3];
  327           when {49 .. 64}:
  328             t1 := ord((b1 & d1) | (c1 & ~d1)) + k1[4];
  329             t2 := ord((b2 & c2) | (~b2 & d2)) + k2[4];
  330           when {65 .. 80}:
  331             t1 := ord(b1 >< (c1 | ~d1)) + k1[5];
  332             t2 := ord(b2 >< c2 >< d2);  # + k2[5];
  333         end case;
  334         t1 +:= ord(a1) + x[r1[index]];
  335         t1 := ord(rotLeft(bin32(t1 mod 16#100000000), s1[index])) + ord(e1);
  336         a1 := e1;
  337         e1 := d1;
  338         d1 := rotLeft(c1, 10);
  339         c1 := b1;
  340         b1 := bin32(t1 mod 16#100000000);
  341         t2 +:= ord(a2) + x[r2[index]];
  342         t2 := ord(rotLeft(bin32(t2 mod 16#100000000), s2[index])) + ord(e2);
  343         a2 := e2;
  344         e2 := d2;
  345         d2 := rotLeft(c2, 10);
  346         c2 := b2;
  347         b2 := bin32(t2 mod 16#100000000);
  348       end for;
  349 
  350       t1 := (h1 + ord(c1) + ord(d2)) mod 16#100000000;
  351       h1 := (h2 + ord(d1) + ord(e2)) mod 16#100000000;
  352       h2 := (h3 + ord(e1) + ord(a2)) mod 16#100000000;
  353       h3 := (h4 + ord(a1) + ord(b2)) mod 16#100000000;
  354       h4 := (h0 + ord(b1) + ord(c2)) mod 16#100000000;
  355       h0 := t1;
  356     end while;
  357 
  358     # Produce the final hash value:
  359     digest := int32AsFourBytesLe(h0) &
  360               int32AsFourBytesLe(h1) &
  361               int32AsFourBytesLe(h2) &
  362               int32AsFourBytesLe(h3) &
  363               int32AsFourBytesLe(h4);
  364   end func;
  365 
  366 
  367 (**
  368  *  Compute a message digest with the SHA-1 secure hash algorithm.
  369  *  @return the SHA-1 message digest (a string of 20 bytes).
  370  *  @exception RANGE_ERROR If ''message'' contains a character beyond '\255;'.
  371  *)
  372 const func string: sha1 (in var string: message) is func
  373   result
  374     var string: digest is "";
  375   local
  376     var integer: length is 0;
  377     var integer: wordIndex is 1;
  378     var integer: index is 0;
  379     var array bin32: w is 80 times bin32.value;
  380     var integer: h0 is 16#67452301;
  381     var integer: h1 is 16#efcdab89;
  382     var integer: h2 is 16#98badcfe;
  383     var integer: h3 is 16#10325476;
  384     var integer: h4 is 16#c3d2e1f0;
  385     var bin32: a is bin32(0);
  386     var bin32: b is bin32(0);
  387     var bin32: c is bin32(0);
  388     var bin32: d is bin32(0);
  389     var bin32: e is bin32(0);
  390     var bin32: f is bin32(0);
  391     var bin32: g is bin32(0);
  392     var integer: temp is 0;
  393     var integer: k is 0;
  394   begin
  395     length := length(message);
  396     # Append the bit '1' to the message.
  397     message &:= '\16#80;';
  398     # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
  399     message &:= "\0;" mult 63 - (length + 8) mod 64;
  400     # Append length of message (before pre-processing), in bits, as 64-bit big-endian integer.
  401     message &:= int64AsEightBytesBe(8 * length);
  402 
  403     # Process the message in successive 512-bit chunks:
  404     while wordIndex <= length(message) do
  405       # Break chunk into sixteen 32-bit big-endian words.
  406       for index range 1 to 16 do
  407         w[index] := bin32(bytes2Int(message[wordIndex len 4], UNSIGNED, BE));
  408         wordIndex +:= 4;
  409       end for;
  410 
  411       # Extend the sixteen 32-bit words into eighty 32-bit words.
  412       for index range 17 to 80 do
  413         g := w[index-3] >< w[index-8] >< w[index-14] >< w[index-16];
  414         w[index] := rotLeft(g, 1);
  415       end for;
  416 
  417       a := bin32(h0 mod 16#100000000);
  418       b := bin32(h1 mod 16#100000000);
  419       c := bin32(h2 mod 16#100000000);
  420       d := bin32(h3 mod 16#100000000);
  421       e := bin32(h4 mod 16#100000000);
  422 
  423       for index range 1 to 80 do
  424         if index <= 20 then
  425           f := d >< (b & (c >< d));
  426           k := 16#5a827999;
  427         elsif index <= 40 then
  428           f := b >< c >< d;
  429           k := 16#6ed9eba1;
  430         elsif index <= 60 then
  431           f := (b & c) | (d & (b | c));
  432           k := 16#8f1bbcdc;
  433         else
  434           f := b >< c >< d;
  435           k := 16#ca62c1d6;
  436         end if;
  437 
  438         temp := ord(rotLeft(a, 5));
  439         temp +:= ord(f) + ord(e) + k + ord(w[index]);
  440         e := d;
  441         d := c;
  442         c := rotLeft(b, 30);
  443         b := a;
  444         a := bin32(temp mod 16#100000000);
  445       end for;
  446 
  447       # Add this chunk's hash to result so far:
  448       h0 +:= ord(a);
  449       h1 +:= ord(b);
  450       h2 +:= ord(c);
  451       h3 +:= ord(d);
  452       h4 +:= ord(e);
  453     end while;
  454 
  455     # Produce the final hash value:
  456     digest := int32AsFourBytesBe(h0) &
  457               int32AsFourBytesBe(h1) &
  458               int32AsFourBytesBe(h2) &
  459               int32AsFourBytesBe(h3) &
  460               int32AsFourBytesBe(h4);
  461   end func;
  462 
  463 
  464 (**
  465  *  Compute a message digest with the SHA-224 secure hash algorithm.
  466  *  @return the SHA-224 message digest (a string of 28 bytes).
  467  *  @exception RANGE_ERROR If ''message'' contains a character beyond '\255;'.
  468  *)
  469 const func string: sha224 (in var string: message) is func
  470   result
  471     var string: digest is "";
  472   local
  473     # Initialize array of round constants with the first 32 bits of
  474     # the fractional parts of the cube roots of the first 64 primes 2..311.
  475     const array integer: k is [] (
  476         16#428a2f98, 16#71374491, 16#b5c0fbcf, 16#e9b5dba5, 16#3956c25b, 16#59f111f1, 16#923f82a4, 16#ab1c5ed5,
  477         16#d807aa98, 16#12835b01, 16#243185be, 16#550c7dc3, 16#72be5d74, 16#80deb1fe, 16#9bdc06a7, 16#c19bf174,
  478         16#e49b69c1, 16#efbe4786, 16#0fc19dc6, 16#240ca1cc, 16#2de92c6f, 16#4a7484aa, 16#5cb0a9dc, 16#76f988da,
  479         16#983e5152, 16#a831c66d, 16#b00327c8, 16#bf597fc7, 16#c6e00bf3, 16#d5a79147, 16#06ca6351, 16#14292967,
  480         16#27b70a85, 16#2e1b2138, 16#4d2c6dfc, 16#53380d13, 16#650a7354, 16#766a0abb, 16#81c2c92e, 16#92722c85,
  481         16#a2bfe8a1, 16#a81a664b, 16#c24b8b70, 16#c76c51a3, 16#d192e819, 16#d6990624, 16#f40e3585, 16#106aa070,
  482         16#19a4c116, 16#1e376c08, 16#2748774c, 16#34b0bcb5, 16#391c0cb3, 16#4ed8aa4a, 16#5b9cca4f, 16#682e6ff3,
  483         16#748f82ee, 16#78a5636f, 16#84c87814, 16#8cc70208, 16#90befffa, 16#a4506ceb, 16#bef9a3f7, 16#c67178f2);
  484     var integer: length is 0;
  485     var integer: wordIndex is 1;
  486     var integer: index is 0;
  487     var array bin32: w is 64 times bin32.value;
  488     # Initialize hash values with the second 32 bits of
  489     # the fractional parts of the square roots of the 9th through 16th primes 23..53.
  490     var integer: h0 is 16#c1059ed8;
  491     var integer: h1 is 16#367cd507;
  492     var integer: h2 is 16#3070dd17;
  493     var integer: h3 is 16#f70e5939;
  494     var integer: h4 is 16#ffc00b31;
  495     var integer: h5 is 16#68581511;
  496     var integer: h6 is 16#64f98fa7;
  497     var integer: h7 is 16#befa4fa4;
  498     var bin32: a is bin32(0);
  499     var bin32: b is bin32(0);
  500     var bin32: c is bin32(0);
  501     var bin32: d is bin32(0);
  502     var bin32: e is bin32(0);
  503     var bin32: f is bin32(0);
  504     var bin32: g is bin32(0);
  505     var bin32: h is bin32(0);
  506     var bin32: s0 is bin32(0);
  507     var bin32: s1 is bin32(0);
  508     var integer: temp1 is 0;
  509     var integer: temp2 is 0;
  510     var bin32: ch is bin32(0);
  511     var bin32: maj is bin32(0);
  512   begin
  513     length := length(message);
  514     # Append the bit '1' to the message.
  515     message &:= '\16#80;';
  516     # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
  517     message &:= "\0;" mult 63 - (length + 8) mod 64;
  518     # Append length of message (before pre-processing), in bits, as 64-bit big-endian integer.
  519     message &:= int64AsEightBytesBe(8 * length);
  520 
  521     # Process the message in successive 512-bit chunks:
  522     while wordIndex <= length(message) do
  523       # Break chunk into sixteen 32-bit big-endian words.
  524       for index range 1 to 16 do
  525         w[index] := bin32(bytes2Int(message[wordIndex len 4], UNSIGNED, BE));
  526         wordIndex +:= 4;
  527       end for;
  528 
  529       # Extend the first 16 words into the remaining 48 words of message schedule array:
  530       for index range 17 to 64 do
  531         w[index] := bin32(ord(w[index-16]) +
  532                           ord(rotRight(w[index-15], 7) >< rotRight(w[index-15], 18) >< (w[index-15] >> 3)) +
  533                           ord(w[index-7]) +
  534                           ord(rotRight(w[index-2], 17) >< rotRight(w[index-2], 19) >< (w[index-2] >> 10))) &
  535                     bin32(16#ffffffff);
  536       end for;
  537 
  538       # Initialize working variables to current hash value:
  539       a := bin32(h0 mod 16#100000000);
  540       b := bin32(h1 mod 16#100000000);
  541       c := bin32(h2 mod 16#100000000);
  542       d := bin32(h3 mod 16#100000000);
  543       e := bin32(h4 mod 16#100000000);
  544       f := bin32(h5 mod 16#100000000);
  545       g := bin32(h6 mod 16#100000000);
  546       h := bin32(h7 mod 16#100000000);
  547 
  548       # Compression function main loop:
  549       for index range 1 to 64 do
  550         s1 := rotRight(e, 6) >< rotRight(e, 11) >< rotRight(e, 25);
  551         ch := (e & f) >< ((bin32(16#ffffffff) >< e) & g);
  552         temp1 := ord(h) + ord(s1) + ord(ch) + k[index] + ord(w[index]);
  553         s0 := rotRight(a, 2) >< rotRight(a, 13) >< rotRight(a, 22);
  554         maj := (a & b) >< (a & c) >< (b & c);
  555         temp2 := ord(s0) + ord(maj);
  556 
  557         h := g;
  558         g := f;
  559         f := e;
  560         e := bin32((ord(d) + temp1) mod 16#100000000);
  561         d := c;
  562         c := b;
  563         b := a;
  564         a := bin32((temp1 + temp2) mod 16#100000000);
  565       end for;
  566 
  567       # Add the compressed chunk to the current hash value:
  568       h0 +:= ord(a);
  569       h1 +:= ord(b);
  570       h2 +:= ord(c);
  571       h3 +:= ord(d);
  572       h4 +:= ord(e);
  573       h5 +:= ord(f);
  574       h6 +:= ord(g);
  575       h7 +:= ord(h);
  576     end while;
  577 
  578     # Produce the final hash value:
  579     digest := int32AsFourBytesBe(h0) &
  580               int32AsFourBytesBe(h1) &
  581               int32AsFourBytesBe(h2) &
  582               int32AsFourBytesBe(h3) &
  583               int32AsFourBytesBe(h4) &
  584               int32AsFourBytesBe(h5) &
  585               int32AsFourBytesBe(h6);
  586   end func;
  587 
  588 
  589 (**
  590  *  Compute a message digest with the SHA-256 secure hash algorithm.
  591  *  @return the SHA-256 message digest (a string of 32 bytes).
  592  *  @exception RANGE_ERROR If ''message'' contains a character beyond '\255;'.
  593  *)
  594 const func string: sha256 (in var string: message) is func
  595   result
  596     var string: digest is "";
  597   local
  598     # Initialize array of round constants with the first 32 bits of
  599     # the fractional parts of the cube roots of the first 64 primes 2..311.
  600     const array integer: k is [] (
  601         16#428a2f98, 16#71374491, 16#b5c0fbcf, 16#e9b5dba5, 16#3956c25b, 16#59f111f1, 16#923f82a4, 16#ab1c5ed5,
  602         16#d807aa98, 16#12835b01, 16#243185be, 16#550c7dc3, 16#72be5d74, 16#80deb1fe, 16#9bdc06a7, 16#c19bf174,
  603         16#e49b69c1, 16#efbe4786, 16#0fc19dc6, 16#240ca1cc, 16#2de92c6f, 16#4a7484aa, 16#5cb0a9dc, 16#76f988da,
  604         16#983e5152, 16#a831c66d, 16#b00327c8, 16#bf597fc7, 16#c6e00bf3, 16#d5a79147, 16#06ca6351, 16#14292967,
  605         16#27b70a85, 16#2e1b2138, 16#4d2c6dfc, 16#53380d13, 16#650a7354, 16#766a0abb, 16#81c2c92e, 16#92722c85,
  606         16#a2bfe8a1, 16#a81a664b, 16#c24b8b70, 16#c76c51a3, 16#d192e819, 16#d6990624, 16#f40e3585, 16#106aa070,
  607         16#19a4c116, 16#1e376c08, 16#2748774c, 16#34b0bcb5, 16#391c0cb3, 16#4ed8aa4a, 16#5b9cca4f, 16#682e6ff3,
  608         16#748f82ee, 16#78a5636f, 16#84c87814, 16#8cc70208, 16#90befffa, 16#a4506ceb, 16#bef9a3f7, 16#c67178f2);
  609     var integer: length is 0;
  610     var integer: wordIndex is 1;
  611     var integer: index is 0;
  612     var array bin32: w is 64 times bin32.value;
  613     # Initialize hash values with the first 32 bits of
  614     # the fractional parts of the square roots of the first 8 primes 2..19.
  615     var integer: h0 is 16#6a09e667;
  616     var integer: h1 is 16#bb67ae85;
  617     var integer: h2 is 16#3c6ef372;
  618     var integer: h3 is 16#a54ff53a;
  619     var integer: h4 is 16#510e527f;
  620     var integer: h5 is 16#9b05688c;
  621     var integer: h6 is 16#1f83d9ab;
  622     var integer: h7 is 16#5be0cd19;
  623     var bin32: a is bin32(0);
  624     var bin32: b is bin32(0);
  625     var bin32: c is bin32(0);
  626     var bin32: d is bin32(0);
  627     var bin32: e is bin32(0);
  628     var bin32: f is bin32(0);
  629     var bin32: g is bin32(0);
  630     var bin32: h is bin32(0);
  631     var bin32: s0 is bin32(0);
  632     var bin32: s1 is bin32(0);
  633     var integer: temp1 is 0;
  634     var integer: temp2 is 0;
  635     var bin32: ch is bin32(0);
  636     var bin32: maj is bin32(0);
  637   begin
  638     length := length(message);
  639     # Append the bit '1' to the message.
  640     message &:= '\16#80;';
  641     # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
  642     message &:= "\0;" mult 63 - (length + 8) mod 64;
  643     # Append length of message (before pre-processing), in bits, as 64-bit big-endian integer.
  644     message &:= int64AsEightBytesBe(8 * length);
  645 
  646     # Process the message in successive 512-bit chunks:
  647     while wordIndex <= length(message) do
  648       # Break chunk into sixteen 32-bit big-endian words.
  649       for index range 1 to 16 do
  650         w[index] := bin32(bytes2Int(message[wordIndex len 4], UNSIGNED, BE));
  651         wordIndex +:= 4;
  652       end for;
  653 
  654       # Extend the first 16 words into the remaining 48 words of message schedule array:
  655       for index range 17 to 64 do
  656         w[index] := bin32(ord(w[index-16]) +
  657                           ord(rotRight(w[index-15], 7) >< rotRight(w[index-15], 18) >< (w[index-15] >> 3)) +
  658                           ord(w[index-7]) +
  659                           ord(rotRight(w[index-2], 17) >< rotRight(w[index-2], 19) >< (w[index-2] >> 10))) &
  660                     bin32(16#ffffffff);
  661       end for;
  662 
  663       # Initialize working variables to current hash value:
  664       a := bin32(h0 mod 16#100000000);
  665       b := bin32(h1 mod 16#100000000);
  666       c := bin32(h2 mod 16#100000000);
  667       d := bin32(h3 mod 16#100000000);
  668       e := bin32(h4 mod 16#100000000);
  669       f := bin32(h5 mod 16#100000000);
  670       g := bin32(h6 mod 16#100000000);
  671       h := bin32(h7 mod 16#100000000);
  672 
  673       # Compression function main loop:
  674       for index range 1 to 64 do
  675         s1 := rotRight(e, 6) >< rotRight(e, 11) >< rotRight(e, 25);
  676         ch := (e & f) >< ((bin32(16#ffffffff) >< e) & g);
  677         temp1 := ord(h) + ord(s1) + ord(ch) + k[index] + ord(w[index]);
  678         s0 := rotRight(a, 2) >< rotRight(a, 13) >< rotRight(a, 22);
  679         maj := (a & b) >< (a & c) >< (b & c);
  680         temp2 := ord(s0) + ord(maj);
  681 
  682         h := g;
  683         g := f;
  684         f := e;
  685         e := bin32((ord(d) + temp1) mod 16#100000000);
  686         d := c;
  687         c := b;
  688         b := a;
  689         a := bin32((temp1 + temp2) mod 16#100000000);
  690       end for;
  691 
  692       # Add the compressed chunk to the current hash value:
  693       h0 +:= ord(a);
  694       h1 +:= ord(b);
  695       h2 +:= ord(c);
  696       h3 +:= ord(d);
  697       h4 +:= ord(e);
  698       h5 +:= ord(f);
  699       h6 +:= ord(g);
  700       h7 +:= ord(h);
  701     end while;
  702 
  703     # Produce the final hash value:
  704     digest := int32AsFourBytesBe(h0) &
  705               int32AsFourBytesBe(h1) &
  706               int32AsFourBytesBe(h2) &
  707               int32AsFourBytesBe(h3) &
  708               int32AsFourBytesBe(h4) &
  709               int32AsFourBytesBe(h5) &
  710               int32AsFourBytesBe(h6) &
  711               int32AsFourBytesBe(h7);
  712   end func;
  713 
  714 
  715 (**
  716  *  Compute a message digest with the SHA-384 secure hash algorithm.
  717  *  @return the SHA-384 message digest (a string of 48 bytes).
  718  *  @exception RANGE_ERROR If ''message'' contains a character beyond '\255;'.
  719  *)
  720 const func string: sha384 (in var string: message) is func
  721   result
  722     var string: digest is "";
  723   local
  724     const bigInteger: powTwo64 is 2_**64;
  725     # Initialize array of round constants with the first 64 bits of
  726     # the fractional parts of the cube roots of the first 80 primes 2..409.
  727     const array bigInteger: k is [] (
  728         16#428a2f98d728ae22_, 16#7137449123ef65cd_, 16#b5c0fbcfec4d3b2f_, 16#e9b5dba58189dbbc_,
  729         16#3956c25bf348b538_, 16#59f111f1b605d019_, 16#923f82a4af194f9b_, 16#ab1c5ed5da6d8118_,
  730         16#d807aa98a3030242_, 16#12835b0145706fbe_, 16#243185be4ee4b28c_, 16#550c7dc3d5ffb4e2_,
  731         16#72be5d74f27b896f_, 16#80deb1fe3b1696b1_, 16#9bdc06a725c71235_, 16#c19bf174cf692694_,
  732         16#e49b69c19ef14ad2_, 16#efbe4786384f25e3_, 16#0fc19dc68b8cd5b5_, 16#240ca1cc77ac9c65_,
  733         16#2de92c6f592b0275_, 16#4a7484aa6ea6e483_, 16#5cb0a9dcbd41fbd4_, 16#76f988da831153b5_,
  734         16#983e5152ee66dfab_, 16#a831c66d2db43210_, 16#b00327c898fb213f_, 16#bf597fc7beef0ee4_,
  735         16#c6e00bf33da88fc2_, 16#d5a79147930aa725_, 16#06ca6351e003826f_, 16#142929670a0e6e70_,
  736         16#27b70a8546d22ffc_, 16#2e1b21385c26c926_, 16#4d2c6dfc5ac42aed_, 16#53380d139d95b3df_,
  737         16#650a73548baf63de_, 16#766a0abb3c77b2a8_, 16#81c2c92e47edaee6_, 16#92722c851482353b_,
  738         16#a2bfe8a14cf10364_, 16#a81a664bbc423001_, 16#c24b8b70d0f89791_, 16#c76c51a30654be30_,
  739         16#d192e819d6ef5218_, 16#d69906245565a910_, 16#f40e35855771202a_, 16#106aa07032bbd1b8_,
  740         16#19a4c116b8d2d0c8_, 16#1e376c085141ab53_, 16#2748774cdf8eeb99_, 16#34b0bcb5e19b48a8_,
  741         16#391c0cb3c5c95a63_, 16#4ed8aa4ae3418acb_, 16#5b9cca4f7763e373_, 16#682e6ff3d6b2b8a3_,
  742         16#748f82ee5defb2fc_, 16#78a5636f43172f60_, 16#84c87814a1f0ab72_, 16#8cc702081a6439ec_,
  743         16#90befffa23631e28_, 16#a4506cebde82bde9_, 16#bef9a3f7b2c67915_, 16#c67178f2e372532b_,
  744         16#ca273eceea26619c_, 16#d186b8c721c0c207_, 16#eada7dd6cde0eb1e_, 16#f57d4f7fee6ed178_,
  745         16#06f067aa72176fba_, 16#0a637dc5a2c898a6_, 16#113f9804bef90dae_, 16#1b710b35131c471b_,
  746         16#28db77f523047d84_, 16#32caab7b40c72493_, 16#3c9ebe0a15c9bebc_, 16#431d67c49c100d4c_,
  747         16#4cc5d4becb3e42b6_, 16#597f299cfc657e2a_, 16#5fcb6fab3ad6faec_, 16#6c44198c4a475817_);
  748     var integer: length is 0;
  749     var integer: chunkIndex is 0;
  750     var integer: index is 0;
  751     var array bin64: w is 80 times bin64.value;
  752     # Initialize hash values with the first 64 bits of
  753     # the fractional parts of the square roots of the first 8 primes 2..19.
  754     var bigInteger: h0 is 16#cbbb9d5dc1059ed8_;
  755     var bigInteger: h1 is 16#629a292a367cd507_;
  756     var bigInteger: h2 is 16#9159015a3070dd17_;
  757     var bigInteger: h3 is 16#152fecd8f70e5939_;
  758     var bigInteger: h4 is 16#67332667ffc00b31_;
  759     var bigInteger: h5 is 16#8eb44a8768581511_;
  760     var bigInteger: h6 is 16#db0c2e0d64f98fa7_;
  761     var bigInteger: h7 is 16#47b5481dbefa4fa4_;
  762     var bin64: a is bin64(0);
  763     var bin64: b is bin64(0);
  764     var bin64: c is bin64(0);
  765     var bin64: d is bin64(0);
  766     var bin64: e is bin64(0);
  767     var bin64: f is bin64(0);
  768     var bin64: g is bin64(0);
  769     var bin64: h is bin64(0);
  770     var bin64: s0 is bin64(0);
  771     var bin64: s1 is bin64(0);
  772     var bin64: temp1 is bin64(0);
  773     var bin64: temp2 is bin64(0);
  774     var bin64: ch is bin64(0);
  775     var bin64: maj is bin64(0);
  776   begin
  777     length := length(message);
  778     # Append the bit '1' to the message.
  779     message &:= '\16#80;';
  780     # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 1024).
  781     message &:= "\0;" mult 127 - (length + 8) mod 128;
  782     # Append length of message (before pre-processing), in bits, as 64-bit big-endian integer.
  783     message &:= int64AsEightBytesBe(8 * length);
  784 
  785     # Process the message in successive 1024-bit chunks:
  786     for chunkIndex range 1 to length(message) step 128 do
  787       # Check that the input contains no character beyond '\255;'.
  788       for index range 0 to 127 do
  789         if ord(message[chunkIndex + index]) > 255 then
  790           raise RANGE_ERROR;
  791         end if;
  792       end for;
  793 
  794       # Break chunk into sixteen 64-bit big-endian words.
  795       for index range 1 to 16 do
  796         w[index] := bin64(message[chunkIndex + 8 * pred(index) len 8], BE);
  797       end for;
  798 
  799       # Extend the first 16 words into the remaining 64 words of message schedule array:
  800       for index range 17 to 80 do
  801         w[index] := bin64((big(w[index-16]) +
  802                            big(rotRight(w[index-15], 1) ><
  803                                rotRight(w[index-15], 8) ><
  804                                (w[index-15] >> 7)) +
  805                            big(w[index-7]) +
  806                            big(rotRight(w[index-2], 19) ><
  807                                rotRight(w[index-2], 61) ><
  808                                (w[index-2] >> 6))) mod powTwo64);
  809       end for;
  810 
  811       # Initialize working variables to current hash value:
  812       a := bin64(h0 mod powTwo64);
  813       b := bin64(h1 mod powTwo64);
  814       c := bin64(h2 mod powTwo64);
  815       d := bin64(h3 mod powTwo64);
  816       e := bin64(h4 mod powTwo64);
  817       f := bin64(h5 mod powTwo64);
  818       g := bin64(h6 mod powTwo64);
  819       h := bin64(h7 mod powTwo64);
  820 
  821       # Compression function main loop:
  822       for index range 1 to 80 do
  823         s1 := rotRight(e, 14) >< rotRight(e, 18) >< rotRight(e, 41);
  824         ch := (e & f) >< (~e & g);
  825         temp1 := bin64((big(h) + big(s1) + big(ch) + k[index] + big(w[index])) mod powTwo64);
  826         s0 := rotRight(a, 28) >< rotRight(a, 34) >< rotRight(a, 39);
  827         maj := (a & b) >< (a & c) >< (b & c);
  828         temp2 := bin64((big(s0) + big(maj)) mod powTwo64);
  829 
  830         h := g;
  831         g := f;
  832         f := e;
  833         e := bin64((big(d) + big(temp1)) mod powTwo64);
  834         d := c;
  835         c := b;
  836         b := a;
  837         a := bin64((big(temp1) + big(temp2)) mod powTwo64);
  838       end for;
  839 
  840       # Add the compressed chunk to the current hash value:
  841       h0 +:= big(a);
  842       h1 +:= big(b);
  843       h2 +:= big(c);
  844       h3 +:= big(d);
  845       h4 +:= big(e);
  846       h5 +:= big(f);
  847       h6 +:= big(g);
  848       h7 +:= big(h);
  849     end for;
  850 
  851     # Produce the final hash value:
  852     digest := bigAsEightBytesBe(h0) &
  853               bigAsEightBytesBe(h1) &
  854               bigAsEightBytesBe(h2) &
  855               bigAsEightBytesBe(h3) &
  856               bigAsEightBytesBe(h4) &
  857               bigAsEightBytesBe(h5);
  858   end func;
  859 
  860 
  861 (**
  862  *  Compute a message digest with the SHA-512 secure hash algorithm.
  863  *  @return the SHA-512 message digest (a string of 64 bytes).
  864  *  @exception RANGE_ERROR If ''message'' contains a character beyond '\255;'.
  865  *)
  866 const func string: sha512 (in var string: message) is func
  867   result
  868     var string: digest is "";
  869   local
  870     const bigInteger: powTwo64 is 2_**64;
  871     # Initialize array of round constants with the first 64 bits of
  872     # the fractional parts of the cube roots of the first 80 primes 2..409.
  873     const array bigInteger: k is [] (
  874         16#428a2f98d728ae22_, 16#7137449123ef65cd_, 16#b5c0fbcfec4d3b2f_, 16#e9b5dba58189dbbc_,
  875         16#3956c25bf348b538_, 16#59f111f1b605d019_, 16#923f82a4af194f9b_, 16#ab1c5ed5da6d8118_,
  876         16#d807aa98a3030242_, 16#12835b0145706fbe_, 16#243185be4ee4b28c_, 16#550c7dc3d5ffb4e2_,
  877         16#72be5d74f27b896f_, 16#80deb1fe3b1696b1_, 16#9bdc06a725c71235_, 16#c19bf174cf692694_,
  878         16#e49b69c19ef14ad2_, 16#efbe4786384f25e3_, 16#0fc19dc68b8cd5b5_, 16#240ca1cc77ac9c65_,
  879         16#2de92c6f592b0275_, 16#4a7484aa6ea6e483_, 16#5cb0a9dcbd41fbd4_, 16#76f988da831153b5_,
  880         16#983e5152ee66dfab_, 16#a831c66d2db43210_, 16#b00327c898fb213f_, 16#bf597fc7beef0ee4_,
  881         16#c6e00bf33da88fc2_, 16#d5a79147930aa725_, 16#06ca6351e003826f_, 16#142929670a0e6e70_,
  882         16#27b70a8546d22ffc_, 16#2e1b21385c26c926_, 16#4d2c6dfc5ac42aed_, 16#53380d139d95b3df_,
  883         16#650a73548baf63de_, 16#766a0abb3c77b2a8_, 16#81c2c92e47edaee6_, 16#92722c851482353b_,
  884         16#a2bfe8a14cf10364_, 16#a81a664bbc423001_, 16#c24b8b70d0f89791_, 16#c76c51a30654be30_,
  885         16#d192e819d6ef5218_, 16#d69906245565a910_, 16#f40e35855771202a_, 16#106aa07032bbd1b8_,
  886         16#19a4c116b8d2d0c8_, 16#1e376c085141ab53_, 16#2748774cdf8eeb99_, 16#34b0bcb5e19b48a8_,
  887         16#391c0cb3c5c95a63_, 16#4ed8aa4ae3418acb_, 16#5b9cca4f7763e373_, 16#682e6ff3d6b2b8a3_,
  888         16#748f82ee5defb2fc_, 16#78a5636f43172f60_, 16#84c87814a1f0ab72_, 16#8cc702081a6439ec_,
  889         16#90befffa23631e28_, 16#a4506cebde82bde9_, 16#bef9a3f7b2c67915_, 16#c67178f2e372532b_,
  890         16#ca273eceea26619c_, 16#d186b8c721c0c207_, 16#eada7dd6cde0eb1e_, 16#f57d4f7fee6ed178_,
  891         16#06f067aa72176fba_, 16#0a637dc5a2c898a6_, 16#113f9804bef90dae_, 16#1b710b35131c471b_,
  892         16#28db77f523047d84_, 16#32caab7b40c72493_, 16#3c9ebe0a15c9bebc_, 16#431d67c49c100d4c_,
  893         16#4cc5d4becb3e42b6_, 16#597f299cfc657e2a_, 16#5fcb6fab3ad6faec_, 16#6c44198c4a475817_);
  894     var integer: length is 0;
  895     var integer: chunkIndex is 0;
  896     var integer: index is 0;
  897     var array bin64: w is 80 times bin64.value;
  898     # Initialize hash values with the first 64 bits of
  899     # the fractional parts of the square roots of the first 8 primes 2..19.
  900     var bigInteger: h0 is 16#6a09e667f3bcc908_;
  901     var bigInteger: h1 is 16#bb67ae8584caa73b_;
  902     var bigInteger: h2 is 16#3c6ef372fe94f82b_;
  903     var bigInteger: h3 is 16#a54ff53a5f1d36f1_;
  904     var bigInteger: h4 is 16#510e527fade682d1_;
  905     var bigInteger: h5 is 16#9b05688c2b3e6c1f_;
  906     var bigInteger: h6 is 16#1f83d9abfb41bd6b_;
  907     var bigInteger: h7 is 16#5be0cd19137e2179_;
  908     var bin64: a is bin64(0);
  909     var bin64: b is bin64(0);
  910     var bin64: c is bin64(0);
  911     var bin64: d is bin64(0);
  912     var bin64: e is bin64(0);
  913     var bin64: f is bin64(0);
  914     var bin64: g is bin64(0);
  915     var bin64: h is bin64(0);
  916     var bin64: s0 is bin64(0);
  917     var bin64: s1 is bin64(0);
  918     var bin64: temp1 is bin64(0);
  919     var bin64: temp2 is bin64(0);
  920     var bin64: ch is bin64(0);
  921     var bin64: maj is bin64(0);
  922   begin
  923     length := length(message);
  924     # Append the bit '1' to the message.
  925     message &:= '\16#80;';
  926     # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 1024).
  927     message &:= "\0;" mult 127 - (length + 8) mod 128;
  928     # Append length of message (before pre-processing), in bits, as 64-bit big-endian integer.
  929     message &:= int64AsEightBytesBe(8 * length);
  930 
  931     # Process the message in successive 1024-bit chunks:
  932     for chunkIndex range 1 to length(message) step 128 do
  933       # Check that the input contains no character beyond '\255;'.
  934       for index range 0 to 127 do
  935         if ord(message[chunkIndex + index]) > 255 then
  936           raise RANGE_ERROR;
  937         end if;
  938       end for;
  939 
  940       # Break chunk into sixteen 64-bit big-endian words.
  941       for index range 1 to 16 do
  942         w[index] := bin64(message[chunkIndex + 8 * pred(index) len 8], BE);
  943       end for;
  944 
  945       # Extend the first 16 words into the remaining 64 words of message schedule array:
  946       for index range 17 to 80 do
  947         w[index] := bin64((big(w[index-16]) +
  948                            big(rotRight(w[index-15], 1) ><
  949                                rotRight(w[index-15], 8) ><
  950                                (w[index-15] >> 7)) +
  951                            big(w[index-7]) +
  952                            big(rotRight(w[index-2], 19) ><
  953                                rotRight(w[index-2], 61) ><
  954                                (w[index-2] >> 6))) mod powTwo64);
  955       end for;
  956 
  957       # Initialize working variables to current hash value:
  958       a := bin64(h0 mod powTwo64);
  959       b := bin64(h1 mod powTwo64);
  960       c := bin64(h2 mod powTwo64);
  961       d := bin64(h3 mod powTwo64);
  962       e := bin64(h4 mod powTwo64);
  963       f := bin64(h5 mod powTwo64);
  964       g := bin64(h6 mod powTwo64);
  965       h := bin64(h7 mod powTwo64);
  966 
  967       # Compression function main loop:
  968       for index range 1 to 80 do
  969         s1 := rotRight(e, 14) >< rotRight(e, 18) >< rotRight(e, 41);
  970         ch := (e & f) >< (~e & g);
  971         temp1 := bin64((big(h) + big(s1) + big(ch) + k[index] + big(w[index])) mod powTwo64);
  972         s0 := rotRight(a, 28) >< rotRight(a, 34) >< rotRight(a, 39);
  973         maj := (a & b) >< (a & c) >< (b & c);
  974         temp2 := bin64((big(s0) + big(maj)) mod powTwo64);
  975 
  976         h := g;
  977         g := f;
  978         f := e;
  979         e := bin64((big(d) + big(temp1)) mod powTwo64);
  980         d := c;
  981         c := b;
  982         b := a;
  983         a := bin64((big(temp1) + big(temp2)) mod powTwo64);
  984       end for;
  985 
  986       # Add the compressed chunk to the current hash value:
  987       h0 +:= big(a);
  988       h1 +:= big(b);
  989       h2 +:= big(c);
  990       h3 +:= big(d);
  991       h4 +:= big(e);
  992       h5 +:= big(f);
  993       h6 +:= big(g);
  994       h7 +:= big(h);
  995     end for;
  996 
  997     # Produce the final hash value:
  998     digest := bigAsEightBytesBe(h0) &
  999               bigAsEightBytesBe(h1) &
 1000               bigAsEightBytesBe(h2) &
 1001               bigAsEightBytesBe(h3) &
 1002               bigAsEightBytesBe(h4) &
 1003               bigAsEightBytesBe(h5) &
 1004               bigAsEightBytesBe(h6) &
 1005               bigAsEightBytesBe(h7);
 1006   end func;
 1007 
 1008 
 1009 (**
 1010  *  Enumeration of message digest algorithms.
 1011  *  Defines: NO_DIGEST, MD4, MD5, RIPEMD160, SHA1, SHA224, SHA256, SHA384 and SHA512.
 1012  *)
 1013 const type: digestAlgorithm is new enum
 1014     NO_DIGEST, MD4, MD5, RIPEMD160, SHA1, SHA224, SHA256, SHA384, SHA512
 1015   end enum;
 1016 
 1017 
 1018 (**
 1019  *  Compute a message digest with the given [[msgdigest#digestAlgorithm|digestAlgorithm]].
 1020  *  @param digestAlg The [[msgdigest#digestAlgorithm|digestAlgorithm]] to be used.
 1021  *  @return the message digest of the ''message''.
 1022  *  @exception RANGE_ERROR If ''message'' contains a character beyond '\255;'.
 1023  *)
 1024 const func string: msgDigest (in digestAlgorithm: digestAlg, in string: message) is DYNAMIC;
 1025 
 1026 const func string: msgDigest (NO_DIGEST, in string: message) is return "";
 1027 const func string: msgDigest (MD4, in string: message)       is return md4(message);
 1028 const func string: msgDigest (MD5, in string: message)       is return md5(message);
 1029 const func string: msgDigest (RIPEMD160, in string: message) is return ripemd160(message);
 1030 const func string: msgDigest (SHA1, in string: message)      is return sha1(message);
 1031 const func string: msgDigest (SHA224, in string: message)    is return sha224(message);
 1032 const func string: msgDigest (SHA256, in string: message)    is return sha256(message);
 1033 const func string: msgDigest (SHA384, in string: message)    is return sha384(message);
 1034 const func string: msgDigest (SHA512, in string: message)    is return sha512(message);
 1035 
 1036 
 1037 (**
 1038  *  Block size used by the given [[msgdigest#digestAlgorithm|digestAlgorithm]].
 1039  *  @return the block size in bytes used by the message digest algorithm.
 1040  *)
 1041 const func integer: blockSize (in digestAlgorithm: digestAlg) is DYNAMIC;
 1042 
 1043 const func integer: blockSize (NO_DIGEST) is   0;
 1044 const func integer: blockSize (MD4)       is  64;
 1045 const func integer: blockSize (MD5)       is  64;
 1046 const func integer: blockSize (RIPEMD160) is  64;
 1047 const func integer: blockSize (SHA1)      is  64;
 1048 const func integer: blockSize (SHA224)    is  64;
 1049 const func integer: blockSize (SHA256)    is  64;
 1050 const func integer: blockSize (SHA384)    is 128;
 1051 const func integer: blockSize (SHA512)    is 128;
 1052 
 1053 
 1054 (**
 1055  *  Size of a message digest computed with the given [[msgdigest#digestAlgorithm|digestAlgorithm]].
 1056  *  @return the size of a message digest in bytes.
 1057  *)
 1058 const func integer: digestSize (in digestAlgorithm: digestAlg) is DYNAMIC;
 1059 
 1060 const func integer: digestSize (NO_DIGEST) is  0;
 1061 const func integer: digestSize (MD4)       is 16;
 1062 const func integer: digestSize (MD5)       is 16;
 1063 const func integer: digestSize (RIPEMD160) is 20;
 1064 const func integer: digestSize (SHA1)      is 20;
 1065 const func integer: digestSize (SHA224)    is 28;
 1066 const func integer: digestSize (SHA256)    is 32;
 1067 const func integer: digestSize (SHA384)    is 48;
 1068 const func integer: digestSize (SHA512)    is 64;