Geschichte
Die Secure Hash Algorithmen ist eine Gruppe von vier Hashing-Algorithmen, welche vom National Institute of Standards and Technology (NIST) veröffentlicht wurden.
Der erste Algorithmus der SHA-Gruppe ist der im Jahre 1993 veröffentlichte, damals genannte, SHA-Algorithmus. Der Algorithmus wurde schnell wieder zurückgezogen, da ein signifikanter Fehler darin entdeckt wurde.
Der neuste SHA3-Algorithmus gewann im Oktober 2012 einen von NIST organisierten Wettbewerb. Damals war er als Keccak-Algorithmus bekannt.
Gebrauch
Die neueren, sicheren Algorithmen der SHA-Gruppe werden oft gebraucht, um Passwörter zu hashen und so auf Servern abzuspeichern.
Der SHA-256-Algorithmus wird beim Generieren von digitalen Signaturen für HTTPS-Certificates benutzt.
Bei der Cryptocurrency Ethereum wird mit dem SHA3-Algorithmus die Adresse eines Users generiert.
Funktionsweise
Hier wird die Funktion des SHA3- (bzw. Keccak-) Algorithmus erläutert.
Bitwise XOR wird als ^ geschrieben und ein Bitwise AND als &.
Das Hashen
Um eine Nachricht S zu hashen, wird sie zuerst zu einem Binarystring konvertiert. Zu diesem Binarystring wird dann der für den SHA-3 charakteristischen Suffix [0, 1] angehängt.
Der Binarystring wird dann in Chunks geteilt, dessen Länge der Rate entspricht (2 × die Outputlänge).
Diese Chunks werden dann Gepaddet und zu States konvertiert.
Auf jeden State A wird dann das Five-Step-Mapping angewendet.
Ab dem zweiten State wird er jeweils vor dem Five-Step-Mapping mit dem vorherig modifizierten State ge-XOR-t.
Nachdem alle States modifiziert wurden und somit die Nachricht gehasht, wird der State zurück zu einem Binarystring konvertiert und dessen erste Outputlänge Bits werden schlussendlich zu einem Little-Endian-Hexstring konvertiert und als Hashvalue der Nachricht zurückgegeben.
Variablen
Hier werden die wichtigsten Variablen des SHA3-Algorithmus aufgelistet.
- A: Der State.
- b: Die Breite der Keccak-Permutation, bei SHA3 1600.
- w: Die Lane-Size, bzw. b / 25.
- l: Der Logarithmus Basis 2 von w, bei SHA3 6.
- nr: Wie viele Male das Five-Step-Mapping auf einen State angewendet wird, 12 + 2 × l, bei SHA3 24.
- Outputlänge: Wie lange das Hashvalue in Bits sein soll, bei SHA3 entweder 224, 256, 384 oder 512.
- Kapazität: Wie viele Bits einer Nachricht in einen State aufgenommen werden, 2 × die Outputlänge.
- Rate: Wie viele Bits das Padding eines States ausmachen sollen, b - die Kapazität.
Padding
Beim SHA3-Algorithmus wird der Input mit dem pad10*1-Algorithmus gepaddet.
Beim pad10*1-Algorithmus wird zuerst ein Bit mit Wert 1 angehängt, danach so viele Bits mit Wert 0, dass die Länge des Inputs + 1 Modulo die Rate (b - 2 × die Outputlänge) Null entspricht und schlussendlich wird nochmals ein Bit mit Wert 1 angehängt.
Konvertierung von Strings zu State-Arrays
Die Konvertierung eines Strings S zu einem State-Array A läuft wie folgt ab:
Für alle Triplets (x, y, z), so dass 0 ≤ x < 5, 0 ≤ y < 5 und 0 ≤ z < w, lass
A[x, y, z] = S[w × (5 × y + x) + z].
Konvertierung von State-Arrays zu Strings
Die Konvertierung eines States A zu einem String S läuft wie folgt ab:
Für die Konvertierung werden genestete For-Loops gebraucht, welche zuerst über alle z iterieren, dann x und schlussendlich y.
Für alle Triplets (x, y, z), so dass 0 ≤ x < 5, 0 ≤ y < 5 und 0 ≤ z < w, lass
S += A[x, y, z].
Five-Step-Mapping
Das Five-Step-Mapping modifiziert den State so, dass nach dem Mapping nicht mehr auf den originalen State zurückzuführen ist.
Pro State wird nr (12 + 2 × l, bzw beim SHA3-Algorithmus 24) mal das Five-Step-Mapping auf den State angewendet.
Die Funktion des Five-Step-Mappings sieht wie folgt aus:
iota(chi(pi(rho(theta(A)))), i)
Wobei A der State ist, welcher modifiziert wird und i der Index der momentanen Runde.
θ (Theta)
- Für alle Paare (x, z), so dass 0 ≤ x < 5 und 0 ≤ z < w, lass
- C[x, z] = A[x, 0, z] ^ A[x, 1, z] ^ A[x, 2, z] ^ A[x, 3, z] ^ A[x, 4, z].
- Für alle Paare (x, z), so dass 0 ≤ x < 5 und 0 ≤ z < w, lass
- D[x, z] = C[(x - 1) mod 5, z] ^ C[(x + 1) mod 5, (z – 1) mod w].
- Für alle Triplets (x, y, z), so dass 0 ≤ x < 5, 0 ≤ y < 5 und 0 ≤ z < w, lass
- A'[x, y, z] = A[x, y, z] ^ D[x, z].
- Gib A' zurück.
- Für alle Paare (x, z), so dass 0 ≤ x < 5 und 0 ≤ z < w, lass
ρ (Rho)
- Für alle z, so dass 0 ≤ z < w, lass A'[0, 0, z] = A[0, 0, z].
- Lass (x, y) = (1, 0).
- Für t von 0 bis und mit 23
- Für alle z, so dass 0 ≤ z < w, lass A'[x, y, z] = A[x, y, (z – (t + 1)(t + 2) / 2) mod w].
- Lass (x, y) = (y, (2 × x + 3 × y) mod 5).
- Gib A' zurück.
π (Pi)
- Für alle Triplets (x, y, z), so dass 0 ≤ x < 5, 0 ≤ y < 5 und 0 ≤ z < w, lass
- A'[x, y, z] = A[(x + 3 × y) mod 5, x, z].
- Gib A' zurück.
- Für alle Triplets (x, y, z), so dass 0 ≤ x < 5, 0 ≤ y < 5 und 0 ≤ z < w, lass
χ (Chi)
- Für alle Triplets (x, y, z), so dass 0 ≤ x < 5, 0 ≤ y < 5 und 0 ≤ z < w, lass
- A'[x, y, z] = A[x, y, z] ^ ((A[x + 1 mod 5, y, z] ^ 1) & A[(x + 2) mod 5, y, z]).
- Gib A' zurück.
- Für alle Triplets (x, y, z), so dass 0 ≤ x < 5, 0 ≤ y < 5 und 0 ≤ z < w, lass
RC (Round-Constant - Hilfsfunktion für ι (Iota))
Diese Funktion nimmt, alles als die Anderen des Five-Step-Mapping, eine Zahl t entgegen (Anstatt einen State A) und gibt ein Bit zurück (Anstatt ein modifizierter State A').
- Falls t mod 255 == 0, gib 1 zurück.
- Lass R = [1, 0, 0, 0, 0, 0, 0, 0].
- Für alle i von 1 bis t mod 255, lass
- R = [0] + R
- R[0] = R[0] ^ R[8]
- R[4] = R[4] ^ R[8]
- R[5] = R[5] ^ R[8]
- R[6] = R[6] ^ R[8]
- R = R[0] bis R[8]
- Gib R[0] zurück.
ι (Iota)
- Für alle Triplets (x, y, z), so dass 0 ≤ x < 5, 0 ≤ y < 5 und 0 ≤ z < w, lass
- A'[x, y, z] = A[x, y, z].
- Lass RC = 0w (Ein Array mit Länge w, gefüllt mit Nullen).
- Für alle j von 0 bis und mit l, lass RC[2j - 1] = rc(j + 7 × ir).
- Für alle z, so dass 0 ≤ z < w, lass A'[0, 0, z] = A'[0, 0, z] ^ RC[z].
- Gib A' zurück.
- Für alle Triplets (x, y, z), so dass 0 ≤ x < 5, 0 ≤ y < 5 und 0 ≤ z < w, lass
Beispielcode
Diese Beispielcodes zeigen mögliche Implementierungen des SHA3-Algorithmus.
Die Namen der Variablen sind meist identisch deren der Federal Information Processing Standards (NIST).
Dies ist ein in Python geschriebener Beispielcode:
# Nötiger Import
from copy import deepcopy
# Die meisten Variablen sind benannt nach den FEDERAL INFORMATION PROCESSING STANDARDS (NIST) (https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf)
# A' wird als aA geschrieben
# Konstanten für die Hash-Funktion
b = 1600; w = 64; l = 6; nr = 12 + 2 * l
# Die Länge des produzierten Hash-Values in Bits
outputLength = 224 # oder: 256 / 384 / 512
# Diese Funktion nimmt einen String entgegen und gibt dessen Hash-Value zurück
def hashSHA(message):
# Die Bits des Parameters mit dem für den SHA3-Algorithmus charakteristischen Suffix [0, 1]
inputBits = stringToBitArray(message) + [0, 1]
# Der momentane State
A = []
# Der Array inputBits wird in (b - 2 * outputLength) grosse Chunks geteilt und an den Array Chunks angehängt
chunks = []
for i in range(len(inputBits) // (b - 2 * outputLength) + 1): chunks.append(inputBits[i * (b - 2 * outputLength):(i + 1) * (b - 2 * outputLength)])
# Über die Chunks wird iteriert
for chunk in chunks:
# Der Chunk wird zu einem State modifiziert
aA = messageBitsToState(chunk)
# Falls bereits über ein Chunk iteriert wurde, wird jedes Bit von aA ge-XOR-t mit dem Bit des momentanen States
if len(A) != 0:
for x in range(5):
for y in range(5):
for z in range(w): aA[x][y][z] ^= A[x][y][z]
# Der momentane State ist nun der neue State
A = aA
# nr mal wird das five step mapping auf den neuen State angewendet
for i in range(nr): A = keccakRound(A, i)
# Der Hash-Value wird zurückgegeben
return stateToLittleEndianHexString(A)[:outputLength // 4] # Dividiert durch vier, da ein Hex-String zurückgegeben wird
# Diese Funktion gibt einen Little-Endian-Hex-String des States A zurück
def stateToLittleEndianHexString(A):
# Der State als Binary-String
binString = stateToBinString(A)
hexString = ''
# Über jedes Byte wird iteriert
for i in range(len(binString) // 8):
# Das Byte wird zu einem Little-Endian-Hex-Value konvertiert
byte = hex(int((binString[i * 8:(i + 1) * 8])[::-1], 2))[2:]
# Das Byte wird gepaddet, damit es zwei Characters lang ist
byte = (2 - len(byte)) * '0' + byte
# Das Byte wird zum hexString hinzugefügt
hexString += byte
return hexString
# Diese Funktion konvertiert einen State zu einem Binary-String
def stateToBinString(A):
# Der Algorithmus gemäss den FEDERAL INFORMATION PROCESSING STANDARDS
binStr = ''
for y in range(5):
for x in range(5): binStr += ''.join(str(i) for i in A[x][y])
return binStr
# Diese Funktion konvertiert die Bits einer Nachricht, mit maximaler Länge (b - 2 * outputLength), zu einem State
def messageBitsToState(bitArray):
# Der Input wird gepaddet
aA = bitPadding(bitArray)
# Der State
A = []
# Der Algorithmus gemäss den FEDERAL INFORMATION PROCESSING STANDARDS
for x in range(5):
yArr = []
for y in range(5):
zArr = []
for z in range(w): zArr.append(aA[w * (5 * y + x) + z])
yArr.append(zArr)
A.append(yArr)
# Der neue State wird zurückgegeben
return A
# Diese Funktion konvertiert einen String zu einem Binary-Array
def stringToBitArray(string):
# Der Binary-Array
arr = []
# Über jeden Character des Strings wird iteriert
for char in string:
# Der Character als Little-Endian-Binary-String
byte = (bin(ord(char))[2:])[::-1]
# Das Byte wird gepaddet
while len(byte) < 8: byte += '0'
# Zum Array wird jedes Bit des Bytes angehängt
arr += [int(bit) for bit in byte]
return arr
# Diese Funktion gibt den Array zurück, nachdem die pad10*1 Funktion darauf angewendet wurde
def bitPadding(arr):
# Die Kapazität des Algorithmus
capacity = 2 * outputLength
# Die Rate des Algorithmus
rate = b - capacity
# Falls der Array schon rate Bits lange ist, muss die Rate nicht gepaddet werden
if len(arr) != rate:
# Zum Array wird ein Bit mit Wert 1 angehängt, danach so viele Bits mit Wert 0, bis die Länge des Arrays der Rate entspricht
# danach wird nochmals ein Bit mit Wert 1angehängt
zeros = (-len(arr) - 2) % rate
arr.append(1)
arr += zeros * [0]
arr.append(1)
# Der Array wird mit Bits mit Wert 0 gefüllt, bis dessen Länge b entspricht
while len(arr) % b != 0: arr.append(0)
return arr
# Gibt den State zurück, nachdem das five step mapping darauf angewendet wurde
keccakRound = lambda A, i: iota(chi(pi(rho(theta(A)))), i)
# Die erste Funktion des five step mappings
def theta(A):
C = []
for x in range(5):
CArr = []
for z in range(w):
num = 0
for y in range(5): num ^= A[x][y][z]
CArr.append(num)
C.append(CArr)
D = []
for x in range(5):
zArr = []
for z in range(w): zArr.append(C[(((x - 1) % 5) + 5) % 5][z] ^ C[(x + 1) % 5][(((z - 1) % w) + w) % w])
D.append(zArr)
aA = A
for x in range(5):
for y in range(5):
for z in range(w): aA[x][y][z] = A[x][y][z] ^ D[x][z]
return aA
# Die zweite Funktion des five step mappings
def rho(A):
aA = deepcopy(A)
x = 1; y = 0
for t in range(24):
for z in range(w): aA[x][y][(z + (t + 1) * (t + 2) // 2) % w] = A[x][y][z]
x, y = y, (2 * x + 3 * y) % 5
return aA
# Die dritte Funktion des five step mappings
def pi(A):
aA = deepcopy(A)
for x in range(5):
for y in range(5):
for z in range(w): aA[x][y][z] = A[(x + 3 * y) % 5][x][z]
return aA
# Die vierte Funktion des five step mappings
def chi(A):
aA = deepcopy(A)
for x in range(5):
for y in range(5):
for z in range(w): aA[x][y][z] ^= (A[(x + 1) % 5][y][z] ^ 1) & A[(x + 2) % 5][y][z]
return aA
# Die fünfte Funktion des five step mappings
def iota(A, i):
RC = w * [0]
for j in range(l + 1): RC[2 ** j - 1] = roundConstant(j + 7 * i)
for z in range(w): A[0][0][z] ^= RC[z]
return A
# Diese Funktion gibt eine Konstante zurück, welche von der Rundennummer abhängt. Wird von der Funktion iota gerufen
def roundConstant(t):
if t % 255 == 0: return 1
R = [1, 0, 0, 0, 0, 0, 0, 0]
for i in range(t % 255):
R = [0] + R
R[0] ^= R[8]
R[4] ^= R[8]
R[5] ^= R[8]
R[6] ^= R[8]
R = R[:-1]
return R[0]
Es werden Booleans gebraucht, um die Bits darzustellen, um den nötigen Speicherplatz zu minimieren. True ist ein Bit mit Wert 1, während False ein Bit mit Wert 0 ist.
Dies ist ein in Java geschriebener Beispielcode:
// Nötige Imports
import java.util.Arrays;
import java.lang.Math;
.
.
.
// Die meisten Variablen sind benannt nach den FEDERAL INFORMATION PROCESSING STANDARDS (NIST) (https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf)
// A' wird als aA geschrieben
// Konstanten für die Hash-Funktion
public static final int b = 1600, w = 64, l = 6, nr = 12 + 2 * l;
// Die Länge des produzierten Hash-Values in Bits
public static final int outputLength = 224; // oder : 256 / 384 / 512
// Diese Funktion nimmt einen String entgegen und gibt dessen Hash-Value zurück
public static String hashSHA(String message) {
// Kreierung des Arrays inputBits, die message als Bits mit dem für den SHA3-Algorithmus charakteristischen Suffix [0, 1]
boolean[] messageBits = stringToBitArray(message);
boolean[] inputBits = new boolean[messageBits.length + 2];
System.arraycopy(messageBits, 0, inputBits, 0, messageBits.length);
System.arraycopy(new boolean[] {false, true}, 0, inputBits, messageBits.length, 2);
// Der momentane State
boolean[][][] A = new boolean[5][5][w];
// Der Array inputBits wird in (b - 2 * outputLength) grosse Chunks geteilt und zum Array Chunks angehängt
String[] chunks = new String[inputBits.length / (b - 2 * outputLength) + 1];
for (int i = 0; i < inputBits.length / (b - 2 * outputLength) + 1; i++) {
// Der i-te Teil des Arrays inputBits mit Länge (b - 2 * outputLength) wird in chunks[i] kopiert
chunks[i] = "";
int strLength = (inputBits.length - i * (b - 2 * outputLength)) % (b - 2 * outputLength);
for (int j = 0; j < b - 2 * outputLength && i * (b - 2 * outputLength) + j < inputBits.length; j++) chunks[i] += inputBits[i * (b - 2 * outputLength) + j] ? '1' : '0';
}
// Iteriere über die Chunks
for (String chunk : chunks) {
// Der Chunks wird zu einem State modifiziert
boolean[][][] aA = messageBitsToState(chunk);
// Jedes bit von aA wird ge-XOR-t mit dem Bit des momentanen States
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
for (int z = 0; z < w; z++) aA[x][y][z] ^= A[x][y][z];
}
}
// Der momentane State ist nun der neue State
A = aA;
// nr mal wird das five step mapping auf den neuen State angewendet
for (int i = 0; i < nr; i++) A = keccakRound(A, i);
}
// Der Hash-Value wird zurückgegeben
return stateToLittleEndianHexString(A).substring(0, outputLength / 4);
}
// Diese Funktion gibt einen Little-Endian-Hex-String des States A zurück
public static String stateToLittleEndianHexString(boolean[][][] A) {
// Der State als Binary-String
String binString = stateToBinString(A);
String hexString = "";
// Über jedes Byte wird iteriert
for (int i = 0; i < binString.length() / 8; i++) {
// Das byte wird zu einem Little-Endian-Hex-Value konvertiert
String curByte = binString.substring(i * 8, (i + 1) * 8);
// Der curByte wird reversed, bzw. zu Little-Endian konvertiert
String reversedByte = "";
for (int j = 7; j >= 0; j--) reversedByte += curByte.charAt(j);
curByte = reversedByte;
// Konvertiere den Binary String zu einem Hex String
curByte = Integer.toHexString(Integer.parseInt(curByte, 2));
// Das Byte wird gepaddet, damit es zwei Characters lang ist
curByte = "0".repeat(2 - curByte.length()) + curByte;
// Das Byte wird zum HexString hinzugefügt
hexString += curByte;
}
return hexString;
}
// Diese Funktion konvertiert einen State zu einem Binary-String
public static String stateToBinString(boolean[][][] A) {
// Der Algorithmus gemäss den FEDERAL INFORMATION PROCESSING STANDARDS
String binStr = "";
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
for (int z = 0; z < w; z++) {
binStr += Integer.toBinaryString(A[x][y][z] ? 1 : 0);
}
}
}
return binStr;
}
// Diese Funktion konvertiert die Bits einer Nachricht, mit maximaler Länge (b - 2 * outputLength), zu einem State
public static boolean[][][] messageBitsToState(String bitString) {
boolean[] bitArray = new boolean[bitString.length()];
for (int i = 0; i < bitArray.length; i++) bitArray[i] = bitString.charAt(i) == '1';
// Der Input wird gepaddet
boolean[] aA = bitPadding(bitArray);
// Der State
boolean[][][] A = new boolean[5][5][w];
// Der Algorithmus gemäss den FEDERAL INFORMATION PROCESSING STANDARDS
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
for (int z = 0; z < w; z++) A[x][y][z] = aA[w * (5 * y + x) + z];
}
}
// Der neue State wird zurückgegeben
return A;
}
// Diese Funktion konvertiert einen String zu einem Binary-Array
public static boolean[] stringToBitArray(String str) {
// Der Binary-Array
boolean[] arr = new boolean[str.length() * 8];
int index = 0;
// Über jeden Character des Strings wird iteriert
for (int i = 0; i < str.length(); i++) {
// Der Character als Binary-String
String binStr = Integer.toBinaryString((int)str.charAt(i));
// Der Character wird zu Little-Endian konvertiert
String reversedbinStr = "";
for (int j = binStr.length() - 1; j >= 0; j--) reversedbinStr += binStr.charAt(j);
binStr = reversedbinStr;
// Das Byte wird gepaddet
while (binStr.length() < 8) binStr += "0";
// Zum Array arr wird jedes Bit des Bytes appendet
for (int j = 0; j < binStr.length(); j++, index++) arr[index] = binStr.charAt(j) == '1';
}
return arr;
}
// Diese Funktion gibt den Array zurück, nachdem die pad10*1 Funktion darauf angewendet wurde
public static boolean[] bitPadding(boolean[] arr) {
// Der gepaddete Array, welcher am Schluss zurückgegeben wird
boolean[] paddedArr = new boolean[b];
System.arraycopy(arr, 0, paddedArr, 0, arr.length);
// Die Kapazität des Algorithmus
int capacity = 2 * outputLength;
// Die Rate des Algorithmus
int rate = b - capacity;
// Falls der Array schon rate Bits lange ist, muss die Rate nicht gepaddet werden
if (arr.length != rate) {
// Zum Array wird ein Bit mit Wert 1 angehängt, danach so viele Bits mit Wert 0, bis die Länge des Arrays der Rate entspricht
// danach wird nochmals ein Bit mit Wert 1 angehängt
int zeros = (-arr.length - 2) % rate;
paddedArr[arr.length] = true;
for (int i = arr.length + 2; i < b - 1; i++) paddedArr[i] = false;
paddedArr[rate - 1] = true;
}
for (int i = rate; i < b; i++) paddedArr[i] = false;
return paddedArr;
}
// Gibt den State zurück, nachdem das five step mapping darauf angewendet wurde
public static boolean[][][] keccakRound(boolean[][][] A, int i) {
return iota(chi(pi(rho(theta(A)))), i);
}
// Die erste Funktion des five step mappings
public static boolean[][][] theta(boolean[][][] A) {
boolean[][] C = new boolean[5][w];
for (int x = 0; x < 5; x++) {
for (int z = 0; z < w; z++) {
// Der momentane Bit, welcher bei C[x][z] eingefügt wird
boolean currBit = false;
for (int i = 0; i < 5; i++) currBit ^= A[x][i][z];
C[x][z] = currBit;
}
}
boolean[][] D = new boolean[5][w];
for (int x = 0; x < 5; x++) {
for (int z = 0; z < w; z++) {
D[x][z] = C[(((x - 1) % 5) + 5) % 5][z] ^ C[(x + 1) % 5][((z - 1) % w + w) % w];
}
}
boolean[][][] aA = new boolean[5][5][w];
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
for (int z = 0; z < w; z++) aA[x][y][z] = A[x][y][z] ^ D[x][z];
}
}
return aA;
}
// Die zweite Funktion des five step mappings
public static boolean[][][] rho(boolean[][][] A) {
boolean[][][] aA = new boolean[5][5][w];
for (int z = 0; z < w; z++) aA[0][0][z] = A[0][0][z];
int x = 1, y = 0, xTemp;
for (int t = 0; t < 24; t++) {
for (int z = 0; z < w; z++) aA[x][y][(z + (t + 1) * (t + 2) / 2) % w] = A[x][y][z];
xTemp = x;
x = y;
y = (2 * xTemp + 3 * y) % 5;
}
return aA;
}
// Die dritte Funktion des five step mappings
public static boolean[][][] pi(boolean[][][] A) {
boolean[][][] aA = new boolean[5][5][w];
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
for (int z = 0; z < w; z++) aA[x][y][z] = A[(x + 3 * y) % 5][x][z];
}
}
return aA;
}
// Die vierte Funktion des five step mappings
public static boolean[][][] chi(boolean[][][] A) {
boolean[][][] aA = new boolean[5][5][w];
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
for (int z = 0; z < w; z++) aA[x][y][z] = A[x][y][z] ^ (A[(x + 1) % 5][y][z] ^ true) & A[(x + 2) % 5][y][z];
}
}
return aA;
}
// Die fünfte Funktion des five step mappings
public static boolean[][][] iota(boolean[][][] A, int i) {
// Automatisch ausgefüllt mit false (Bits von Wert 0)
boolean[] RC = new boolean[w];
for (int j = 0; j <= l; j++) RC[(int)Math.pow(2, j) - 1] = roundConstant(j + 7 * i);
for (int z = 0; z < w; z++) A[0][0][z] ^= RC[z];
return A;
}
// Diese Funktion gibt eine Konstante zurück, welche von der Rundennummer abhängt. Wird von der Funktion iota gerufen
public static boolean roundConstant(int t) {
if (t % 255 == 0) return true;
// R verkörpert ein Byte mit Startwert 10000000
boolean[] R = {true, false, false, false, false, false, false, false};
for (int i = 0; i < t % 255; i++) {
// Das Bit, welches verloren geht nach dem Verschieben des Arrays
boolean lostBit = R[7];
// Shifte jeden Wert von R um eins nach rechts
for (int j = 6; j >= 0; j--) R[j + 1] = R[j];
R[0] = false;
R[0] ^= lostBit;
R[4] ^= lostBit;
R[5] ^= lostBit;
R[6] ^= lostBit;
}
return R[0];
}
Input-Hasher
Deine mit dem SHA3--Algorithmus gehashte Nachricht: