Die Konstanten von SHA-256: Ursprung, Bedeutung & Berechnung

SHA-256 nutzt zwei wichtige Konstantengruppen:

Initiale Hash-Werte

Die Startwerte (Initialisierungsvektoren) für den Hash-Zustand bestehen aus acht 32-Bit-Werten. Diese Werte stammen aus den ersten 32 Bits der Quadratwurzeln der ersten acht Primzahlen (2, 3, 5, 7, 11, 13, 17, 19).

Beispiel

  • Quadratwurzel von 2 = 1,4142135623730950488…
  • Nachkommastellen: 0,4142135623730950488 × 2³² ≈ 1779033703 = 0x6a09e667

Diese Werte sind

0x6a09e667
0xbb67ae85
0x3c6ef372
0xa54ff53a
0x510e527f
0x9b05688c
0x1f83d9ab
0x5be0cd19

Rundenschlüssel

SHA-256 verwendet 64 Rundenschlüssel für die 64 Iterationen des Kompressionsalgorithmus. Diese Schlüssel sind die ersten 32 Bits der Kubikwurzeln der ersten 64 Primzahlen (beginnend mit 2).

Beispiel

  • Kubikwurzel von 2 = 1,25992104989487316477…
  • Nachkommastellen: 0,25992104989487316477 × 2³² ≈ 1116352408 = 0x428a2f98

Diese Rundenschlüssel sehen aus wie

0x428a2f98, 0x71374491, 0xb5c0fbcf, ..., 0xc67178f2

Diese Konstanten sorgen für:

  • Nicht-Vorhersagbarkeit: Verhindert analytische Rückführung der Hashes.
  • Diffusion: Kleine Eingabeänderung erzeugt große Hash-Differenz.
  • Sicherheit: Schutz vor Kollisionen, Längenerweiterungs- und Vorabbild-Angriffen.
  • Transparenz: Die Herkunft der Konstanten ist mathematisch definiert („Nothing-up-my-sleeve numbers“).

Berechnung

#!/usr/bin/perl
use strict;
use warnings;

# Berechne die Initial-Hash-Werte (H) und Rundenschlüssel (K)

sub derive_constants {
    my @primes;
    my $n = 2;
    while (@primes < 64) {
        push @primes, $n if is_prime($n);
        $n++;
    }

    my @H;
    for my $p (@primes[0..7]) {
        my $sqrt = sqrt($p);
        my $hex = extract_hex_bits($sqrt);
        push @H, $hex;
    }

    my @K;
    for my $p (@primes[0..63]) {
        my $cbrt = $p ** (1/3);
        my $hex = extract_hex_bits($cbrt);
        push @K, $hex;
    }

    return (\@H, \@K);
}

sub extract_hex_bits {
    my ($num) = @_;
    my $frac = $num - int($num);
    my $val = int($frac * 4294967296); # 2^32
    return sprintf("0x%08x", $val);
}

sub is_prime {
    my $num = shift;
    return 0 if $num < 2;
    for (2..sqrt($num)) {
        return 0 if $num % $_ == 0;
    }
    return 1;
}

my ($H_ref, $K_ref) = derive_constants();

print "Initiale Hash-Werte H:\n";
print join("\n", @$H_ref), "\n\n";

print "Rundenschlüssel K:\n";
print join("\n", @$K_ref), "\n";

Ausgabe

Initiale Hash-Werte H:
0x6a09e667
0xbb67ae85
0x3c6ef372
0xa54ff53a
0x510e527f
0x9b05688c
0x1f83d9ab
0x5be0cd19

Rundenschlüssel K:
0x428a2f98
0x71374491
0xb5c0fbcf
0xe9b5dba5
0x3956c25b
0x59f111f1
0x923f82a4
0xab1c5ed5
0xd807aa98
0x12835b01
0x243185be
0x550c7dc3
0x72be5d74
0x80deb1fe
0x9bdc06a7
0xc19bf174
0xe49b69c1
0xefbe4786
0x0fc19dc6
0x240ca1cc
0x2de92c6f
0x4a7484aa
0x5cb0a9dc
0x76f988da
0x983e5152
0xa831c66d
0xb00327c8
0xbf597fc7
0xc6e00bf3
0xd5a79147
0x06ca6351
0x14292967
0x27b70a85
0x2e1b2138
0x4d2c6dfc
0x53380d13
0x650a7354
0x766a0abb
0x81c2c92e
0x92722c85
0xa2bfe8a1
0xa81a664b
0xc24b8b70
0xc76c51a3
0xd192e819
0xd6990624
0xf40e3585
0x106aa070
0x19a4c116
0x1e376c08
0x2748774c
0x34b0bcb5
0x391c0cb3
0x4ed8aa4a
0x5b9cca4f
0x682e6ff3
0x748f82ee
0x78a5636f
0x84c87814
0x8cc70208
0x90befffa
0xa4506ceb
0xbef9a3f7
0xc67178f2

Siehe auch