Algorithms
Message digest
 previous   up   next 

Compute a message digest with the MD4 message digest algorithm

The function md4 is part of the "msgdigest.s7i" library. The security of MD4 has been severely compromised. This function is provided for backward compatibility.

const func string: md4 (in var string: message) is func
  result
    var string: digest is "";
  local
    # Specify the per-round shift amounts
    const array integer: shiftAmount is [] (
        3,  7, 11, 19,  3,  7, 11, 19,  3,  7, 11, 19,  3,  7, 11, 19,
        3,  5,  9, 13,  3,  5,  9, 13,  3,  5,  9, 13,  3,  5,  9, 13,
        3,  9, 11, 15,  3,  9, 11, 15,  3,  9, 11, 15,  3,  9, 11, 15);
    const array integer: idx is [] (
        1,  9,  5, 13,  3, 11,  7, 15,  2, 10,  6, 14,  4, 12,  8, 16);
    var integer: length is 0;
    var integer: wordIndex is 1;
    var integer: index is 0;
    var array bin32: m is 16 times bin32.value;
    var integer: a0 is 16#67452301;   # a
    var integer: b0 is 16#efcdab89;   # b
    var integer: c0 is 16#98badcfe;   # c
    var integer: d0 is 16#10325476;   # d
    var bin32: a is bin32(0);
    var bin32: b is bin32(0);
    var bin32: c is bin32(0);
    var bin32: d is bin32(0);
    var bin32: f is bin32(0);
    var integer: g is 0;
    var bin32: temp is bin32(0);
  begin
    length := length(message);
    # Append the bit '1' to the message.
    message &:= '\16#80;';
    # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
    message &:= "\0;" mult 63 - (length + 8) mod 64;
    # Append length of message (before pre-processing), in bits, as 64-bit little-endian integer.
    message &:= bytes(8 * length, UNSIGNED, LE, 8);

    # Process the message in successive 512-bit chunks:
    while wordIndex <= length(message) do
      # Break chunk into sixteen 32-bit little-endian words.
      for index range 1 to 16 do
        m[index] := bin32(bytes2Int(message[wordIndex fixLen 4], UNSIGNED, LE));
        wordIndex +:= 4;
      end for;

      a := bin32(a0 mod 16#100000000);
      b := bin32(b0 mod 16#100000000);
      c := bin32(c0 mod 16#100000000);
      d := bin32(d0 mod 16#100000000);

      for index range 1 to 48 do
        if index <= 16 then
          f := d >< (b & (c >< d));
          g := index;
        elsif index <= 32 then
          f := bin32(ord(b & (c | d) | (c & d)) + 16#5a827999);
          g := (4 * index + 7) mod 15 + (index mdiv 32) * 15 + 1;
        else
          f := bin32(ord(b >< c >< d) + 16#6ed9eba1);
          g := idx[index - 32];
        end if;
        temp := d;
        d := c;
        c := b;
        b := rotLeft(bin32((ord(a) + ord(f) + ord(m[g])) mod 16#100000000),
                     shiftAmount[index]);
        a := temp;
      end for;

      # Add this chunk's hash to result so far:
      a0 +:= ord(a);
      b0 +:= ord(b);
      c0 +:= ord(c);
      d0 +:= ord(d);
    end while;

    # Produce the final hash value:
    digest := bytes(a0 mod 16#100000000, UNSIGNED, LE, 4) &
              bytes(b0 mod 16#100000000, UNSIGNED, LE, 4) &
              bytes(c0 mod 16#100000000, UNSIGNED, LE, 4) &
              bytes(d0 mod 16#100000000, UNSIGNED, LE, 4);
  end func;

Compute a message digest with the MD5 message digest algorithm

The function md5 is part of the "msgdigest.s7i" library. MD5 is considered to be cryptographically broken. This function is provided for backward compatibility.

# Use binary integer part of the sines of integers (Radians) as constants:
const func array integer: createMd5Table is func
  result
    var array integer: k is 64 times 0;
  local
    var integer: index is 0;
  begin
    for index range 1 to 64 do
      k[index] := trunc(abs(sin(flt(index))) * 2.0 ** 32);
    end for;
  end func;

const func string: md5 (in var string: message) is func
  result
    var string: digest is "";
  local
    # Specify the per-round shift amounts
    const array integer: shiftAmount is [] (
        7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,
        5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,
        4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,
        6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21);
    const array integer: k is createMd5Table;
    var integer: length is 0;
    var integer: wordIndex is 1;
    var integer: index is 0;
    var array bin32: m is 16 times bin32.value;
    var integer: a0 is 16#67452301;   # a
    var integer: b0 is 16#efcdab89;   # b
    var integer: c0 is 16#98badcfe;   # c
    var integer: d0 is 16#10325476;   # d
    var bin32: a is bin32(0);
    var bin32: b is bin32(0);
    var bin32: c is bin32(0);
    var bin32: d is bin32(0);
    var bin32: f is bin32(0);
    var integer: g is 0;
    var bin32: temp is bin32(0);
  begin
    length := length(message);
    # Append the bit '1' to the message.
    message &:= '\16#80;';
    # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
    message &:= "\0;" mult 63 - (length + 8) mod 64;
    # Append length of message (before pre-processing), in bits, as 64-bit little-endian integer.
    message &:= bytes(8 * length, UNSIGNED, LE, 8);

    # Process the message in successive 512-bit chunks:
    while wordIndex <= length(message) do
      # Break chunk into sixteen 32-bit little-endian words.
      for index range 1 to 16 do
        m[index] := bin32(bytes2Int(message[wordIndex fixLen 4], UNSIGNED, LE));
        wordIndex +:= 4;
      end for;

      a := bin32(a0 mod 16#100000000);
      b := bin32(b0 mod 16#100000000);
      c := bin32(c0 mod 16#100000000);
      d := bin32(d0 mod 16#100000000);

      for index range 1 to 64 do
        if index <= 16 then
          f := d >< (b & (c >< d));
          g := index;
        elsif index <= 32 then
          f := c >< (d & (b >< c));
          g := succ((5 * index - 4) mod 16);
        elsif index <= 48 then
          f := b >< c >< d;
          g := succ((3 * index + 2) mod 16);
        else
          f := c >< (b | (bin32(16#ffffffff) >< d));
          g := succ((7 * pred(index)) mod 16);
        end if;

        temp := d;
        d := c;
        c := b;
        b := bin32((ord(b) +
             ord(rotLeft(bin32((ord(a) + ord(f) + k[index] + ord(m[g])) mod 16#100000000),
                         shiftAmount[index]))) mod 16#100000000);
        a := temp;
      end for;

      # Add this chunk's hash to result so far:
      a0 +:= ord(a);
      b0 +:= ord(b);
      c0 +:= ord(c);
      d0 +:= ord(d);
    end while;

    # Produce the final hash value:
    digest := bytes(a0 mod 16#100000000, UNSIGNED, LE, 4) &
              bytes(b0 mod 16#100000000, UNSIGNED, LE, 4) &
              bytes(c0 mod 16#100000000, UNSIGNED, LE, 4) &
              bytes(d0 mod 16#100000000, UNSIGNED, LE, 4);
  end func;

Compute a message digest with the RIPEMD-160 message digest algorithm

The function ripemd160 is part of the "msgdigest.s7i" library.

const func string: ripemd160 (in var string: message) is func
  result
    var string: digest is "";
  local
    const array integer: k1 is [] (16#00000000, 16#5a827999, 16#6ed9eba1, 16#8f1bbcdc, 16#a953fd4e);
    const array integer: k2 is [] (16#50a28be6, 16#5c4dd124, 16#6d703ef3, 16#7a6d76e9, 16#00000000);
    const array integer: r1 is [] (
         1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
         8,  5, 14,  2, 11,  7, 16,  4, 13,  1, 10,  6,  3, 15, 12,  9,
         4, 11, 15,  5, 10, 16,  9,  2,  3,  8,  1,  7, 14, 12,  6, 13,
         2, 10, 12, 11,  1,  9, 13,  5, 14,  4,  8, 16, 15,  6,  7,  3,
         5,  1,  6, 10,  8, 13,  3, 11, 15,  2,  4,  9, 12,  7, 16, 14);
    const array integer: r2 is [] (
         6, 15,  8,  1, 10,  3, 12,  5, 14,  7, 16,  9,  2, 11,  4, 13,
         7, 12,  4,  8,  1, 14,  6, 11, 15, 16,  9, 13,  5, 10,  2,  3,
        16,  6,  2,  4,  8, 15,  7, 10, 12,  9, 13,  3, 11,  1,  5, 14,
         9,  7,  5,  2,  4, 12, 16,  1,  6, 13,  3, 14, 10,  8, 11, 15,
        13, 16, 11,  5,  2,  6,  9,  8,  7,  3, 14, 15,  1,  4, 10, 12);
    const array integer: s1 is [] (
        11, 14, 15, 12,  5,  8,  7,  9, 11, 13, 14, 15,  6,  7,  9,  8,
         7,  6,  8, 13, 11,  9,  7, 15,  7, 12, 15,  9, 11,  7, 13, 12,
        11, 13,  6,  7, 14,  9, 13, 15, 14,  8, 13,  6,  5, 12,  7,  5,
        11, 12, 14, 15, 14, 15,  9,  8,  9, 14,  5,  6,  8,  6,  5, 12,
         9, 15,  5, 11,  6,  8, 13, 12,  5, 12, 13, 14, 11,  8,  5,  6);
    const array integer: s2 is [] (
         8,  9,  9, 11, 13, 15, 15,  5,  7,  7,  8, 11, 14, 14, 12,  6,
         9, 13, 15,  7, 12,  8,  9, 11,  7,  7, 12,  7,  6, 15, 13, 11,
         9,  7, 15, 11,  8,  6,  6, 14, 12, 13,  5, 14, 13, 13,  7,  5,
        15,  5,  8, 11, 14, 14,  6, 14,  6,  9, 12,  9, 12,  5, 15,  8,
         8,  5, 12,  9, 12,  5, 14,  6,  8, 13,  6,  5, 15, 13, 11, 11);
    var integer: length is 0;
    var integer: wordIndex is 1;
    var integer: index is 0;
    var array integer: x is 16 times 0;
    var integer: h0 is 16#67452301;
    var integer: h1 is 16#efcdab89;
    var integer: h2 is 16#98badcfe;
    var integer: h3 is 16#10325476;
    var integer: h4 is 16#c3d2e1f0;
    var bin32: a1 is bin32(0);
    var bin32: b1 is bin32(0);
    var bin32: c1 is bin32(0);
    var bin32: d1 is bin32(0);
    var bin32: e1 is bin32(0);
    var bin32: a2 is bin32(0);
    var bin32: b2 is bin32(0);
    var bin32: c2 is bin32(0);
    var bin32: d2 is bin32(0);
    var bin32: e2 is bin32(0);
    var integer: t1 is 0;
    var integer: t2 is 0;
  begin
    length := length(message);
    # Append the bit '1' to the message.
    message &:= '\16#80;';
    # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
    message &:= "\0;" mult 63 - (length + 8) mod 64;
    # Append length of message (before pre-processing), in bits, as 64-bit little-endian integer.
    message &:= bytes(8 * length, UNSIGNED, LE, 8);

    # Process the message in successive 512-bit chunks:
    while wordIndex <= length(message) do
      # Break chunk into sixteen 32-bit little-endian words.
      for index range 1 to 16 do
        x[index] := bytes2Int(message[wordIndex fixLen 4], UNSIGNED, LE);
        wordIndex +:= 4;
      end for;

      a1 := bin32(h0);
      b1 := bin32(h1);
      c1 := bin32(h2);
      d1 := bin32(h3);
      e1 := bin32(h4);
      a2 := bin32(h0);
      b2 := bin32(h1);
      c2 := bin32(h2);
      d2 := bin32(h3);
      e2 := bin32(h4);

      for index range 1 to 80 do
        case index of
          when {1 .. 16}:
            t1 := ord(b1 >< c1 >< d1);  # + k1[1];
            t2 := ord(b2 >< (c2 | ~d2)) + k2[1];
          when {17 .. 32}:
            t1 := ord((b1 & c1) | (~b1 & d1)) + k1[2];
            t2 := ord((b2 & d2) | (c2 & ~d2)) + k2[2];
          when {33 .. 48}:
            t1 := ord((b1 | ~c1) >< d1) + k1[3];
            t2 := ord((b2 | ~c2) >< d2) + k2[3];
          when {49 .. 64}:
            t1 := ord((b1 & d1) | (c1 & ~d1)) + k1[4];
            t2 := ord((b2 & c2) | (~b2 & d2)) + k2[4];
          when {65 .. 80}:
            t1 := ord(b1 >< (c1 | ~d1)) + k1[5];
            t2 := ord(b2 >< c2 >< d2);  # + k2[5];
        end case;
        t1 +:= ord(a1) + x[r1[index]];
        t1 := ord(rotLeft(bin32(t1 mod 16#100000000), s1[index])) + ord(e1);
        a1 := e1;
        e1 := d1;
        d1 := rotLeft(c1, 10);
        c1 := b1;
        b1 := bin32(t1 mod 16#100000000);
        t2 +:= ord(a2) + x[r2[index]];
        t2 := ord(rotLeft(bin32(t2 mod 16#100000000), s2[index])) + ord(e2);
        a2 := e2;
        e2 := d2;
        d2 := rotLeft(c2, 10);
        c2 := b2;
        b2 := bin32(t2 mod 16#100000000);
      end for;

      t1 := (h1 + ord(c1) + ord(d2)) mod 16#100000000;
      h1 := (h2 + ord(d1) + ord(e2)) mod 16#100000000;
      h2 := (h3 + ord(e1) + ord(a2)) mod 16#100000000;
      h3 := (h4 + ord(a1) + ord(b2)) mod 16#100000000;
      h4 := (h0 + ord(b1) + ord(c2)) mod 16#100000000;
      h0 := t1;
    end while;

    # Produce the final hash value:
    digest := bytes(h0, UNSIGNED, LE, 4) &
              bytes(h1, UNSIGNED, LE, 4) &
              bytes(h2, UNSIGNED, LE, 4) &
              bytes(h3, UNSIGNED, LE, 4) &
              bytes(h4, UNSIGNED, LE, 4);
  end func;

Compute a secure hash value with the SHA-1 algorithm

The function sha1 is part of the "msgdigest.s7i" library.

const func string: sha1 (in var string: message) is func
  result
    var string: digest is "";
  local
    var integer: length is 0;
    var integer: wordIndex is 1;
    var integer: index is 0;
    var array bin32: w is 80 times bin32.value;
    var integer: h0 is 16#67452301;
    var integer: h1 is 16#efcdab89;
    var integer: h2 is 16#98badcfe;
    var integer: h3 is 16#10325476;
    var integer: h4 is 16#c3d2e1f0;
    var bin32: a is bin32(0);
    var bin32: b is bin32(0);
    var bin32: c is bin32(0);
    var bin32: d is bin32(0);
    var bin32: e is bin32(0);
    var bin32: f is bin32(0);
    var bin32: g is bin32(0);
    var integer: temp is 0;
    var integer: k is 0;
  begin
    length := length(message);
    # Append the bit '1' to the message.
    message &:= '\16#80;';
    # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
    message &:= "\0;" mult 63 - (length + 8) mod 64;
    # Append length of message (before pre-processing), in bits, as 64-bit big-endian integer.
    message &:= bytes(8 * length, UNSIGNED, BE, 8);

    # Process the message in successive 512-bit chunks:
    while wordIndex <= length(message) do
      # Break chunk into sixteen 32-bit big-endian words.
      for index range 1 to 16 do
        w[index] := bin32(bytes2Int(message[wordIndex fixLen 4], UNSIGNED, BE));
        wordIndex +:= 4;
      end for;

      # Extend the sixteen 32-bit words into eighty 32-bit words.
      for index range 17 to 80 do
        g := w[index-3] >< w[index-8] >< w[index-14] >< w[index-16];
        w[index] := rotLeft(g, 1);
      end for;

      a := bin32(h0 mod 16#100000000);
      b := bin32(h1 mod 16#100000000);
      c := bin32(h2 mod 16#100000000);
      d := bin32(h3 mod 16#100000000);
      e := bin32(h4 mod 16#100000000);

      for index range 1 to 80 do
        if index <= 20 then
          f := d >< (b & (c >< d));
          k := 16#5a827999;
        elsif index <= 40 then
          f := b >< c >< d;
          k := 16#6ed9eba1;
        elsif index <= 60 then
          f := (b & c) | (d & (b | c));
          k := 16#8f1bbcdc;
        else
          f := b >< c >< d;
          k := 16#ca62c1d6;
        end if;

        temp := ord(rotLeft(a, 5));
        temp +:= ord(f) + ord(e) + k + ord(w[index]);
        e := d;
        d := c;
        c := rotLeft(b, 30);
        b := a;
        a := bin32(temp mod 16#100000000);
      end for;

      # Add this chunk's hash to result so far:
      h0 +:= ord(a);
      h1 +:= ord(b);
      h2 +:= ord(c);
      h3 +:= ord(d);
      h4 +:= ord(e);
    end while;

    # Produce the final hash value:
    digest := bytes(h0 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h1 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h2 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h3 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h4 mod 16#100000000, UNSIGNED, BE, 4);
  end func;

Compute a secure hash value with the SHA-224 algorithm

The function sha224 is part of the "msgdigest.s7i" library.

const func string: sha224 (in var string: message) is func
  result
    var string: digest is "";
  local
    # Initialize array of round constants with the first 32 bits of
    # the fractional parts of the cube roots of the first 64 primes 2..311.
    const array integer: k is [] (
        16#428a2f98, 16#71374491, 16#b5c0fbcf, 16#e9b5dba5, 16#3956c25b, 16#59f111f1, 16#923f82a4, 16#ab1c5ed5,
        16#d807aa98, 16#12835b01, 16#243185be, 16#550c7dc3, 16#72be5d74, 16#80deb1fe, 16#9bdc06a7, 16#c19bf174,
        16#e49b69c1, 16#efbe4786, 16#0fc19dc6, 16#240ca1cc, 16#2de92c6f, 16#4a7484aa, 16#5cb0a9dc, 16#76f988da,
        16#983e5152, 16#a831c66d, 16#b00327c8, 16#bf597fc7, 16#c6e00bf3, 16#d5a79147, 16#06ca6351, 16#14292967,
        16#27b70a85, 16#2e1b2138, 16#4d2c6dfc, 16#53380d13, 16#650a7354, 16#766a0abb, 16#81c2c92e, 16#92722c85,
        16#a2bfe8a1, 16#a81a664b, 16#c24b8b70, 16#c76c51a3, 16#d192e819, 16#d6990624, 16#f40e3585, 16#106aa070,
        16#19a4c116, 16#1e376c08, 16#2748774c, 16#34b0bcb5, 16#391c0cb3, 16#4ed8aa4a, 16#5b9cca4f, 16#682e6ff3,
        16#748f82ee, 16#78a5636f, 16#84c87814, 16#8cc70208, 16#90befffa, 16#a4506ceb, 16#bef9a3f7, 16#c67178f2);
    var integer: length is 0;
    var integer: wordIndex is 1;
    var integer: index is 0;
    var array bin32: w is 64 times bin32.value;
    # Initialize hash values with the second 32 bits of
    # the fractional parts of the square roots of the 9th through 16th primes 23..53.
    var integer: h0 is 16#c1059ed8;
    var integer: h1 is 16#367cd507;
    var integer: h2 is 16#3070dd17;
    var integer: h3 is 16#f70e5939;
    var integer: h4 is 16#ffc00b31;
    var integer: h5 is 16#68581511;
    var integer: h6 is 16#64f98fa7;
    var integer: h7 is 16#befa4fa4;
    var bin32: a is bin32(0);
    var bin32: b is bin32(0);
    var bin32: c is bin32(0);
    var bin32: d is bin32(0);
    var bin32: e is bin32(0);
    var bin32: f is bin32(0);
    var bin32: g is bin32(0);
    var bin32: h is bin32(0);
    var bin32: s0 is bin32(0);
    var bin32: s1 is bin32(0);
    var integer: temp1 is 0;
    var integer: temp2 is 0;
    var bin32: ch is bin32(0);
    var bin32: maj is bin32(0);
  begin
    length := length(message);
    # Append the bit '1' to the message.
    message &:= '\16#80;';
    # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
    message &:= "\0;" mult 63 - (length + 8) mod 64;
    # Append length of message (before pre-processing), in bits, as 64-bit big-endian integer.
    message &:= bytes(8 * length, UNSIGNED, BE, 8);

    # Process the message in successive 512-bit chunks:
    while wordIndex <= length(message) do
      # Break chunk into sixteen 32-bit big-endian words.
      for index range 1 to 16 do
        w[index] := bin32(bytes2Int(message[wordIndex fixLen 4], UNSIGNED, BE));
        wordIndex +:= 4;
      end for;

      # Extend the first 16 words into the remaining 48 words of message schedule array:
      for index range 17 to 64 do
        w[index] := bin32(ord(w[index-16]) +
                          ord(rotRight(w[index-15], 7) >< rotRight(w[index-15], 18) >< (w[index-15] >> 3)) +
                          ord(w[index-7]) +
                          ord(rotRight(w[index-2], 17) >< rotRight(w[index-2], 19) >< (w[index-2] >> 10))) &
                    bin32(16#ffffffff);
      end for;

      # Initialize working variables to current hash value:
      a := bin32(h0 mod 16#100000000);
      b := bin32(h1 mod 16#100000000);
      c := bin32(h2 mod 16#100000000);
      d := bin32(h3 mod 16#100000000);
      e := bin32(h4 mod 16#100000000);
      f := bin32(h5 mod 16#100000000);
      g := bin32(h6 mod 16#100000000);
      h := bin32(h7 mod 16#100000000);

      # Compression function main loop:
      for index range 1 to 64 do
        s1 := rotRight(e, 6) >< rotRight(e, 11) >< rotRight(e, 25);
        ch := (e & f) >< ((bin32(16#ffffffff) >< e) & g);
        temp1 := ord(h) + ord(s1) + ord(ch) + k[index] + ord(w[index]);
        s0 := rotRight(a, 2) >< rotRight(a, 13) >< rotRight(a, 22);
        maj := (a & b) >< (a & c) >< (b & c);
        temp2 := ord(s0) + ord(maj);

        h := g;
        g := f;
        f := e;
        e := bin32((ord(d) + temp1) mod 16#100000000);
        d := c;
        c := b;
        b := a;
        a := bin32((temp1 + temp2) mod 16#100000000);
      end for;

      # Add the compressed chunk to the current hash value:
      h0 +:= ord(a);
      h1 +:= ord(b);
      h2 +:= ord(c);
      h3 +:= ord(d);
      h4 +:= ord(e);
      h5 +:= ord(f);
      h6 +:= ord(g);
      h7 +:= ord(h);
    end while;

    # Produce the final hash value:
    digest := bytes(h0 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h1 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h2 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h3 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h4 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h5 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h6 mod 16#100000000, UNSIGNED, BE, 4);
  end func;

Compute a secure hash value with the SHA-256 algorithm

The function sha256 is part of the "msgdigest.s7i" library.

const func string: sha256 (in var string: message) is func
  result
    var string: digest is "";
  local
    # Initialize array of round constants with the first 32 bits of
    # the fractional parts of the cube roots of the first 64 primes 2..311.
    const array integer: k is [] (
        16#428a2f98, 16#71374491, 16#b5c0fbcf, 16#e9b5dba5, 16#3956c25b, 16#59f111f1, 16#923f82a4, 16#ab1c5ed5,
        16#d807aa98, 16#12835b01, 16#243185be, 16#550c7dc3, 16#72be5d74, 16#80deb1fe, 16#9bdc06a7, 16#c19bf174,
        16#e49b69c1, 16#efbe4786, 16#0fc19dc6, 16#240ca1cc, 16#2de92c6f, 16#4a7484aa, 16#5cb0a9dc, 16#76f988da,
        16#983e5152, 16#a831c66d, 16#b00327c8, 16#bf597fc7, 16#c6e00bf3, 16#d5a79147, 16#06ca6351, 16#14292967,
        16#27b70a85, 16#2e1b2138, 16#4d2c6dfc, 16#53380d13, 16#650a7354, 16#766a0abb, 16#81c2c92e, 16#92722c85,
        16#a2bfe8a1, 16#a81a664b, 16#c24b8b70, 16#c76c51a3, 16#d192e819, 16#d6990624, 16#f40e3585, 16#106aa070,
        16#19a4c116, 16#1e376c08, 16#2748774c, 16#34b0bcb5, 16#391c0cb3, 16#4ed8aa4a, 16#5b9cca4f, 16#682e6ff3,
        16#748f82ee, 16#78a5636f, 16#84c87814, 16#8cc70208, 16#90befffa, 16#a4506ceb, 16#bef9a3f7, 16#c67178f2);
    var integer: length is 0;
    var integer: wordIndex is 1;
    var integer: index is 0;
    var array bin32: w is 64 times bin32.value;
    # Initialize hash values with the first 32 bits of
    # the fractional parts of the square roots of the first 8 primes 2..19.
    var integer: h0 is 16#6a09e667;
    var integer: h1 is 16#bb67ae85;
    var integer: h2 is 16#3c6ef372;
    var integer: h3 is 16#a54ff53a;
    var integer: h4 is 16#510e527f;
    var integer: h5 is 16#9b05688c;
    var integer: h6 is 16#1f83d9ab;
    var integer: h7 is 16#5be0cd19;
    var bin32: a is bin32(0);
    var bin32: b is bin32(0);
    var bin32: c is bin32(0);
    var bin32: d is bin32(0);
    var bin32: e is bin32(0);
    var bin32: f is bin32(0);
    var bin32: g is bin32(0);
    var bin32: h is bin32(0);
    var bin32: s0 is bin32(0);
    var bin32: s1 is bin32(0);
    var integer: temp1 is 0;
    var integer: temp2 is 0;
    var bin32: ch is bin32(0);
    var bin32: maj is bin32(0);
  begin
    length := length(message);
    # Append the bit '1' to the message.
    message &:= '\16#80;';
    # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
    message &:= "\0;" mult 63 - (length + 8) mod 64;
    # Append length of message (before pre-processing), in bits, as 64-bit big-endian integer.
    message &:= bytes(8 * length, UNSIGNED, BE, 8);

    # Process the message in successive 512-bit chunks:
    while wordIndex <= length(message) do
      # Break chunk into sixteen 32-bit big-endian words.
      for index range 1 to 16 do
        w[index] := bin32(bytes2Int(message[wordIndex fixLen 4], UNSIGNED, BE));
        wordIndex +:= 4;
      end for;

      # Extend the first 16 words into the remaining 48 words of message schedule array:
      for index range 17 to 64 do
        w[index] := bin32(ord(w[index-16]) +
                          ord(rotRight(w[index-15], 7) >< rotRight(w[index-15], 18) >< (w[index-15] >> 3)) +
                          ord(w[index-7]) +
                          ord(rotRight(w[index-2], 17) >< rotRight(w[index-2], 19) >< (w[index-2] >> 10))) &
                    bin32(16#ffffffff);
      end for;

      # Initialize working variables to current hash value:
      a := bin32(h0 mod 16#100000000);
      b := bin32(h1 mod 16#100000000);
      c := bin32(h2 mod 16#100000000);
      d := bin32(h3 mod 16#100000000);
      e := bin32(h4 mod 16#100000000);
      f := bin32(h5 mod 16#100000000);
      g := bin32(h6 mod 16#100000000);
      h := bin32(h7 mod 16#100000000);

      # Compression function main loop:
      for index range 1 to 64 do
        s1 := rotRight(e, 6) >< rotRight(e, 11) >< rotRight(e, 25);
        ch := (e & f) >< ((bin32(16#ffffffff) >< e) & g);
        temp1 := ord(h) + ord(s1) + ord(ch) + k[index] + ord(w[index]);
        s0 := rotRight(a, 2) >< rotRight(a, 13) >< rotRight(a, 22);
        maj := (a & b) >< (a & c) >< (b & c);
        temp2 := ord(s0) + ord(maj);

        h := g;
        g := f;
        f := e;
        e := bin32((ord(d) + temp1) mod 16#100000000);
        d := c;
        c := b;
        b := a;
        a := bin32((temp1 + temp2) mod 16#100000000);
      end for;

      # Add the compressed chunk to the current hash value:
      h0 +:= ord(a);
      h1 +:= ord(b);
      h2 +:= ord(c);
      h3 +:= ord(d);
      h4 +:= ord(e);
      h5 +:= ord(f);
      h6 +:= ord(g);
      h7 +:= ord(h);
    end while;

    # Produce the final hash value:
    digest := bytes(h0 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h1 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h2 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h3 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h4 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h5 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h6 mod 16#100000000, UNSIGNED, BE, 4) &
              bytes(h7 mod 16#100000000, UNSIGNED, BE, 4);
  end func;

Compute a secure hash value with the SHA-384 algorithm

Compute a message digest with the SHA-384 secure hash algorithm. The SHA-384 message digest is a string of 48 bytes.

include "bytedata.s7i";
include "bin64.s7i";

const func string: sha384 (in var string: message) is func
  result
    var string: digest is "";
  local
    const bigInteger: powTwo64 is 2_**64;
    # Initialize array of round constants with the first 64 bits of
    # the fractional parts of the cube roots of the first 80 primes 2..409.
    const array bin64: k is [] (
        bin64(16#428a2f98d728ae22_), bin64(16#7137449123ef65cd_), bin64(16#b5c0fbcfec4d3b2f_), bin64(16#e9b5dba58189dbbc_),
        bin64(16#3956c25bf348b538_), bin64(16#59f111f1b605d019_), bin64(16#923f82a4af194f9b_), bin64(16#ab1c5ed5da6d8118_),
        bin64(16#d807aa98a3030242_), bin64(16#12835b0145706fbe_), bin64(16#243185be4ee4b28c_), bin64(16#550c7dc3d5ffb4e2_),
        bin64(16#72be5d74f27b896f_), bin64(16#80deb1fe3b1696b1_), bin64(16#9bdc06a725c71235_), bin64(16#c19bf174cf692694_),
        bin64(16#e49b69c19ef14ad2_), bin64(16#efbe4786384f25e3_), bin64(16#0fc19dc68b8cd5b5_), bin64(16#240ca1cc77ac9c65_),
        bin64(16#2de92c6f592b0275_), bin64(16#4a7484aa6ea6e483_), bin64(16#5cb0a9dcbd41fbd4_), bin64(16#76f988da831153b5_),
        bin64(16#983e5152ee66dfab_), bin64(16#a831c66d2db43210_), bin64(16#b00327c898fb213f_), bin64(16#bf597fc7beef0ee4_),
        bin64(16#c6e00bf33da88fc2_), bin64(16#d5a79147930aa725_), bin64(16#06ca6351e003826f_), bin64(16#142929670a0e6e70_),
        bin64(16#27b70a8546d22ffc_), bin64(16#2e1b21385c26c926_), bin64(16#4d2c6dfc5ac42aed_), bin64(16#53380d139d95b3df_),
        bin64(16#650a73548baf63de_), bin64(16#766a0abb3c77b2a8_), bin64(16#81c2c92e47edaee6_), bin64(16#92722c851482353b_),
        bin64(16#a2bfe8a14cf10364_), bin64(16#a81a664bbc423001_), bin64(16#c24b8b70d0f89791_), bin64(16#c76c51a30654be30_),
        bin64(16#d192e819d6ef5218_), bin64(16#d69906245565a910_), bin64(16#f40e35855771202a_), bin64(16#106aa07032bbd1b8_),
        bin64(16#19a4c116b8d2d0c8_), bin64(16#1e376c085141ab53_), bin64(16#2748774cdf8eeb99_), bin64(16#34b0bcb5e19b48a8_),
        bin64(16#391c0cb3c5c95a63_), bin64(16#4ed8aa4ae3418acb_), bin64(16#5b9cca4f7763e373_), bin64(16#682e6ff3d6b2b8a3_),
        bin64(16#748f82ee5defb2fc_), bin64(16#78a5636f43172f60_), bin64(16#84c87814a1f0ab72_), bin64(16#8cc702081a6439ec_),
        bin64(16#90befffa23631e28_), bin64(16#a4506cebde82bde9_), bin64(16#bef9a3f7b2c67915_), bin64(16#c67178f2e372532b_),
        bin64(16#ca273eceea26619c_), bin64(16#d186b8c721c0c207_), bin64(16#eada7dd6cde0eb1e_), bin64(16#f57d4f7fee6ed178_),
        bin64(16#06f067aa72176fba_), bin64(16#0a637dc5a2c898a6_), bin64(16#113f9804bef90dae_), bin64(16#1b710b35131c471b_),
        bin64(16#28db77f523047d84_), bin64(16#32caab7b40c72493_), bin64(16#3c9ebe0a15c9bebc_), bin64(16#431d67c49c100d4c_),
        bin64(16#4cc5d4becb3e42b6_), bin64(16#597f299cfc657e2a_), bin64(16#5fcb6fab3ad6faec_), bin64(16#6c44198c4a475817_));
    var integer: length is 0;
    var integer: chunkIndex is 0;
    var integer: index is 0;
    var array bin64: w is 80 times bin64.value;
    # Initialize hash values with the first 64 bits of
    # the fractional parts of the square roots of the first 8 primes 2..19.
    var bin64: h0 is bin64(16#cbbb9d5dc1059ed8_);
    var bin64: h1 is bin64(16#629a292a367cd507_);
    var bin64: h2 is bin64(16#9159015a3070dd17_);
    var bin64: h3 is bin64(16#152fecd8f70e5939_);
    var bin64: h4 is bin64(16#67332667ffc00b31_);
    var bin64: h5 is bin64(16#8eb44a8768581511_);
    var bin64: h6 is bin64(16#db0c2e0d64f98fa7_);
    var bin64: h7 is bin64(16#47b5481dbefa4fa4_);
    var bin64: a is bin64(0);
    var bin64: b is bin64(0);
    var bin64: c is bin64(0);
    var bin64: d is bin64(0);
    var bin64: e is bin64(0);
    var bin64: f is bin64(0);
    var bin64: g is bin64(0);
    var bin64: h is bin64(0);
    var bin64: s0 is bin64(0);
    var bin64: s1 is bin64(0);
    var bin64: temp1 is bin64(0);
    var bin64: temp2 is bin64(0);
    var bin64: ch is bin64(0);
    var bin64: maj is bin64(0);
  begin
    length := length(message);
    # Append the bit '1' to the message.
    message &:= '\16#80;';
    # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 1024).
    message &:= "\0;" mult 127 - (length + 8) mod 128;
    # Append length of message (before pre-processing), in bits, as 64-bit big-endian integer.
    message &:= bytes(8 * length, UNSIGNED, BE, 8);

    # Process the message in successive 1024-bit chunks:
    for chunkIndex range 1 to length(message) step 128 do
      # Check that the input contains no character beyond '\255;'.
      for index range 0 to 127 do
        if ord(message[chunkIndex + index]) > 255 then
          raise RANGE_ERROR;
        end if;
      end for;

      # Break chunk into sixteen 64-bit big-endian words.
      for index range 1 to 16 do
        w[index] := bin64(message[chunkIndex + 8 * pred(index) fixLen 8], BE);
      end for;

      # Extend the first 16 words into the remaining 64 words of message schedule array:
      for index range 17 to 80 do
        w[index] := bin64((big(w[index-16]) +
                           big(rotRight(w[index-15], 1) ><
                               rotRight(w[index-15], 8) ><
                               (w[index-15] >> 7)) +
                           big(w[index-7]) +
                           big(rotRight(w[index-2], 19) ><
                               rotRight(w[index-2], 61) ><
                               (w[index-2] >> 6))) mod powTwo64);
      end for;

      # Initialize working variables to current hash value:
      a := h0;
      b := h1;
      c := h2;
      d := h3;
      e := h4;
      f := h5;
      g := h6;
      h := h7;

      # Compression function main loop:
      for index range 1 to 80 do
        s1 := rotRight(e, 14) >< rotRight(e, 18) >< rotRight(e, 41);
        ch := (e & f) >< (~e & g);
        temp1 := bin64((big(h) + big(s1) + big(ch) + big(k[index]) + big(w[index])) mod powTwo64);
        s0 := rotRight(a, 28) >< rotRight(a, 34) >< rotRight(a, 39);
        maj := (a & b) >< (a & c) >< (b & c);
        temp2 := bin64((big(s0) + big(maj)) mod powTwo64);

        h := g;
        g := f;
        f := e;
        e := bin64((big(d) + big(temp1)) mod powTwo64);
        d := c;
        c := b;
        b := a;
        a := bin64((big(temp1) + big(temp2)) mod powTwo64);
      end for;

      # Add the compressed chunk to the current hash value:
      h0 := bin64((big(h0) + big(a)) mod powTwo64);
      h1 := bin64((big(h1) + big(b)) mod powTwo64);
      h2 := bin64((big(h2) + big(c)) mod powTwo64);
      h3 := bin64((big(h3) + big(d)) mod powTwo64);
      h4 := bin64((big(h4) + big(e)) mod powTwo64);
      h5 := bin64((big(h5) + big(f)) mod powTwo64);
      h6 := bin64((big(h6) + big(g)) mod powTwo64);
      h7 := bin64((big(h7) + big(h)) mod powTwo64);
    end for;

    # Produce the final hash value:
    digest := bytes(h0, BE, 8) &
              bytes(h1, BE, 8) &
              bytes(h2, BE, 8) &
              bytes(h3, BE, 8) &
              bytes(h4, BE, 8) &
              bytes(h5, BE, 8);
  end func;

Compute a secure hash value with the SHA-512 algorithm

Compute a message digest with the SHA-512 secure hash algorithm. The SHA-512 message digest is a string of 64 bytes.

include "bytedata.s7i";
include "bin64.s7i";

const func string: sha512 (in var string: message) is func
  result
    var string: digest is "";
  local
    const bigInteger: powTwo64 is 2_**64;
    # Initialize array of round constants with the first 64 bits of
    # the fractional parts of the cube roots of the first 80 primes 2..409.
    const array bin64: k is [] (
        bin64(16#428a2f98d728ae22_), bin64(16#7137449123ef65cd_), bin64(16#b5c0fbcfec4d3b2f_), bin64(16#e9b5dba58189dbbc_),
        bin64(16#3956c25bf348b538_), bin64(16#59f111f1b605d019_), bin64(16#923f82a4af194f9b_), bin64(16#ab1c5ed5da6d8118_),
        bin64(16#d807aa98a3030242_), bin64(16#12835b0145706fbe_), bin64(16#243185be4ee4b28c_), bin64(16#550c7dc3d5ffb4e2_),
        bin64(16#72be5d74f27b896f_), bin64(16#80deb1fe3b1696b1_), bin64(16#9bdc06a725c71235_), bin64(16#c19bf174cf692694_),
        bin64(16#e49b69c19ef14ad2_), bin64(16#efbe4786384f25e3_), bin64(16#0fc19dc68b8cd5b5_), bin64(16#240ca1cc77ac9c65_),
        bin64(16#2de92c6f592b0275_), bin64(16#4a7484aa6ea6e483_), bin64(16#5cb0a9dcbd41fbd4_), bin64(16#76f988da831153b5_),
        bin64(16#983e5152ee66dfab_), bin64(16#a831c66d2db43210_), bin64(16#b00327c898fb213f_), bin64(16#bf597fc7beef0ee4_),
        bin64(16#c6e00bf33da88fc2_), bin64(16#d5a79147930aa725_), bin64(16#06ca6351e003826f_), bin64(16#142929670a0e6e70_),
        bin64(16#27b70a8546d22ffc_), bin64(16#2e1b21385c26c926_), bin64(16#4d2c6dfc5ac42aed_), bin64(16#53380d139d95b3df_),
        bin64(16#650a73548baf63de_), bin64(16#766a0abb3c77b2a8_), bin64(16#81c2c92e47edaee6_), bin64(16#92722c851482353b_),
        bin64(16#a2bfe8a14cf10364_), bin64(16#a81a664bbc423001_), bin64(16#c24b8b70d0f89791_), bin64(16#c76c51a30654be30_),
        bin64(16#d192e819d6ef5218_), bin64(16#d69906245565a910_), bin64(16#f40e35855771202a_), bin64(16#106aa07032bbd1b8_),
        bin64(16#19a4c116b8d2d0c8_), bin64(16#1e376c085141ab53_), bin64(16#2748774cdf8eeb99_), bin64(16#34b0bcb5e19b48a8_),
        bin64(16#391c0cb3c5c95a63_), bin64(16#4ed8aa4ae3418acb_), bin64(16#5b9cca4f7763e373_), bin64(16#682e6ff3d6b2b8a3_),
        bin64(16#748f82ee5defb2fc_), bin64(16#78a5636f43172f60_), bin64(16#84c87814a1f0ab72_), bin64(16#8cc702081a6439ec_),
        bin64(16#90befffa23631e28_), bin64(16#a4506cebde82bde9_), bin64(16#bef9a3f7b2c67915_), bin64(16#c67178f2e372532b_),
        bin64(16#ca273eceea26619c_), bin64(16#d186b8c721c0c207_), bin64(16#eada7dd6cde0eb1e_), bin64(16#f57d4f7fee6ed178_),
        bin64(16#06f067aa72176fba_), bin64(16#0a637dc5a2c898a6_), bin64(16#113f9804bef90dae_), bin64(16#1b710b35131c471b_),
        bin64(16#28db77f523047d84_), bin64(16#32caab7b40c72493_), bin64(16#3c9ebe0a15c9bebc_), bin64(16#431d67c49c100d4c_),
        bin64(16#4cc5d4becb3e42b6_), bin64(16#597f299cfc657e2a_), bin64(16#5fcb6fab3ad6faec_), bin64(16#6c44198c4a475817_));
    var integer: length is 0;
    var integer: chunkIndex is 0;
    var integer: index is 0;
    var array bin64: w is 80 times bin64.value;
    # Initialize hash values with the first 64 bits of
    # the fractional parts of the square roots of the first 8 primes 2..19.
    var bin64: h0 is bin64(16#6a09e667f3bcc908_);
    var bin64: h1 is bin64(16#bb67ae8584caa73b_);
    var bin64: h2 is bin64(16#3c6ef372fe94f82b_);
    var bin64: h3 is bin64(16#a54ff53a5f1d36f1_);
    var bin64: h4 is bin64(16#510e527fade682d1_);
    var bin64: h5 is bin64(16#9b05688c2b3e6c1f_);
    var bin64: h6 is bin64(16#1f83d9abfb41bd6b_);
    var bin64: h7 is bin64(16#5be0cd19137e2179_);
    var bin64: a is bin64(0);
    var bin64: b is bin64(0);
    var bin64: c is bin64(0);
    var bin64: d is bin64(0);
    var bin64: e is bin64(0);
    var bin64: f is bin64(0);
    var bin64: g is bin64(0);
    var bin64: h is bin64(0);
    var bin64: s0 is bin64(0);
    var bin64: s1 is bin64(0);
    var bin64: temp1 is bin64(0);
    var bin64: temp2 is bin64(0);
    var bin64: ch is bin64(0);
    var bin64: maj is bin64(0);
  begin
    length := length(message);
    # Append the bit '1' to the message.
    message &:= '\16#80;';
    # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 1024).
    message &:= "\0;" mult 127 - (length + 8) mod 128;
    # Append length of message (before pre-processing), in bits, as 64-bit big-endian integer.
    message &:= bytes(8 * length, UNSIGNED, BE, 8);

    # Process the message in successive 1024-bit chunks:
    for chunkIndex range 1 to length(message) step 128 do
      # Check that the input contains no character beyond '\255;'.
      for index range 0 to 127 do
        if ord(message[chunkIndex + index]) > 255 then
          raise RANGE_ERROR;
        end if;
      end for;

      # Break chunk into sixteen 64-bit big-endian words.
      for index range 1 to 16 do
        w[index] := bin64(message[chunkIndex + 8 * pred(index) fixLen 8], BE);
      end for;

      # Extend the first 16 words into the remaining 64 words of message schedule array:
      for index range 17 to 80 do
        w[index] := bin64((big(w[index-16]) +
                           big(rotRight(w[index-15], 1) ><
                               rotRight(w[index-15], 8) ><
                               (w[index-15] >> 7)) +
                           big(w[index-7]) +
                           big(rotRight(w[index-2], 19) ><
                               rotRight(w[index-2], 61) ><
                               (w[index-2] >> 6))) mod powTwo64);
      end for;

      # Initialize working variables to current hash value:
      a := h0;
      b := h1;
      c := h2;
      d := h3;
      e := h4;
      f := h5;
      g := h6;
      h := h7;

      # Compression function main loop:
      for index range 1 to 80 do
        s1 := rotRight(e, 14) >< rotRight(e, 18) >< rotRight(e, 41);
        ch := (e & f) >< (~e & g);
        temp1 := bin64((big(h) + big(s1) + big(ch) + big(k[index]) + big(w[index])) mod powTwo64);
        s0 := rotRight(a, 28) >< rotRight(a, 34) >< rotRight(a, 39);
        maj := (a & b) >< (a & c) >< (b & c);
        temp2 := bin64((big(s0) + big(maj)) mod powTwo64);

        h := g;
        g := f;
        f := e;
        e := bin64((big(d) + big(temp1)) mod powTwo64);
        d := c;
        c := b;
        b := a;
        a := bin64((big(temp1) + big(temp2)) mod powTwo64);
      end for;

      # Add the compressed chunk to the current hash value:
      h0 := bin64((big(h0) + big(a)) mod powTwo64);
      h1 := bin64((big(h1) + big(b)) mod powTwo64);
      h2 := bin64((big(h2) + big(c)) mod powTwo64);
      h3 := bin64((big(h3) + big(d)) mod powTwo64);
      h4 := bin64((big(h4) + big(e)) mod powTwo64);
      h5 := bin64((big(h5) + big(f)) mod powTwo64);
      h6 := bin64((big(h6) + big(g)) mod powTwo64);
      h7 := bin64((big(h7) + big(h)) mod powTwo64);
    end for;

    # Produce the final hash value:
    digest := bytes(h0, BE, 8) &
              bytes(h1, BE, 8) &
              bytes(h2, BE, 8) &
              bytes(h3, BE, 8) &
              bytes(h4, BE, 8) &
              bytes(h5, BE, 8) &
              bytes(h6, BE, 8) &
              bytes(h7, BE, 8);
  end func;

 previous   up   next