Die Blockchain in 9 Schritten – Teil 2:
In Teil 1 haben wir die einfachste Blockchain aufgebaut aber am Ende festgestellt, das sie einen Nachteil hat: die einzelnen Datenblöcke sind numerisch aufsteigend sortiert und wir können einzelne Datenblöcke einfach ändern, ohne das diese Veränderung von jemandem bemerkt werden kann.
Auf dieser Webseite wurde das Problem „Schutz vor Veränderung“ unter dem Menüpunkt „F Hash und Mac“ bereits ausgiebig besprochen und so ist es kein Wunder, das unsere Blockchain nun als zusätzlichem Schutz mit einem Hashwert ausgestattet wird, der für jeden Datenblock einzeln berechnet wird. Die einzelnen Datenblöcke werden nun anhand ihrer Hashwerte (und nicht mit einer aufsteigenden Zahlenfolge) miteinander verknüpft.
Schauen wir uns die etwas erweiterte Block-Klasse an:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package net.bplaced.javacrypto.blockchain.step2; /* * Diese Klasse gehört zu BlockChain.java * This class belongs to BlockChain.java */ import java.util.Date; public class Block { public String hash; public String previousHash; private long timeStamp; //as number of milliseconds since 1/1/1970. private String data; public Block(String previousHash, String data) { this.previousHash = previousHash; this.data = data; this.timeStamp = new Date().getTime(); this.hash = calculateHash(); } public String calculateHash() { String calculatedhash = BlockChain.generateSha256( previousHash + Long.toString(timeStamp) + data ); return calculatedhash; } } |
An Stelle der numerischen Felder „number“ und „previousNumber“ treten nun die Stringfelder „hash“ und „previousHash“ sowie das neue Feld „timeStamp“ (also der Zeitstempel der Datenblockerstellung. Die Berechnung des Datenblock-Hashwertes erfolgt durch die Methode „calculateHash“, welche aus dem Inhalt der drei Felder „previousHash“, „timeStamp“ und „data“ einen SHA256-Hashwert berechnet und ihn im Feld „hash“ speichert.
Sehen wir uns nun die Hauptroutine an:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
package net.bplaced.javacrypto.blockchain.step2; /* * Herkunft/Origin: http://javacrypto.bplaced.net/ * Programmierer/Programmer: Michael Fehr * Copyright/Copyright: frei verwendbares Programm (Public Domain) * Copyright: This is free and unencumbered software released into the public domain. * Lizenztext/Licence: <http://unlicense.org> * getestet mit/tested with: Java Runtime Environment 8 Update 191 x64 * getestet mit/tested with: Java Runtime Environment 11.0.1 x64 * Datum/Date (dd.mm.jjjj): 28.05.2019 * Projekt/Project: Blockchain * Funktion: Schritt 2: Verkettung der Liste mit Hashwerten * Function: Step 2: chaining the blocks with hashes * * Sicherheitshinweis/Security notice * Die Programmroutinen dienen nur der Darstellung und haben keinen Anspruch auf eine korrekte Funktion, * insbesondere mit Blick auf die Sicherheit ! * Prüfen Sie die Sicherheit bevor das Programm in der echten Welt eingesetzt wird. * The program routines just show the function but please be aware of the security part - * check yourself before using in the real world ! * * Das Programm benötigt die nachfolgende Bibliothek: * The programm uses this external library: * jar-Datei: https://mvnrepository.com/artifact/com.google.code.gson/gson * * Das Projekt basiert auf dem nachfolgenden Artikel: * The project is based on this article: * https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa */ import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import com.google.gson.GsonBuilder; public class BlockChain { public static ArrayList<Block> blockchain = new ArrayList<Block>(); public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException { System.out.println("I02 BlockChain für Anfänger Stufe 02"); int blockNumber; System.out.println("\nAnzahl Einträge in der blockchain:" + blockchain.size()); // datensatz 1 blockNumber = 1; System.out.println("\nErgänze Block " + blockNumber); addBlock(new Block("0", "Data " + blockNumber)); // genesis block // daten der blockchain System.out.println("Anzahl Einträge in der blockchain:" + blockchain.size()); System.out.println("Inhalt der BlockChain:\n" + getJson(blockchain)); // datensatz 2 blockNumber = 2; System.out.println("\nErgänze Block " + blockNumber); addBlock(new Block(blockchain.get(blockchain.size() - 1).hash, "Data " + blockNumber)); // daten der blockchain System.out.println("Anzahl Einträge in der blockchain:" + blockchain.size()); System.out.println("Inhalt der BlockChain:\n" + getJson(blockchain)); } public static void addBlock(Block newBlock) { blockchain.add(newBlock); } public static String getJson(Object o) { return new GsonBuilder().setPrettyPrinting().create().toJson(o); } public static String generateSha256(String input) { try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] hash = digest.digest(input.getBytes("UTF-8")); StringBuffer hexString = new StringBuffer(); for (int i = 0; i < hash.length; i++) { String hex = Integer.toHexString(0xff & hash[i]); if (hex.length() == 1) hexString.append('0'); hexString.append(hex); } return hexString.toString(); } catch (Exception e) { throw new RuntimeException(e); } } } |
Hier gibt es eine neue Methode ganz am Ende („generateSha256“). Diese Methode sorgt im Wesentlichen dafür, das der Hashwert aus einem String berechnet wird und das Ergebnis wieder einen String ergibt.
Hier folgt nun die Konsolenausgabe:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
I02 BlockChain für Anfänger Stufe 02 Anzahl Einträge in der blockchain:0 Ergänze Block 1 Anzahl Einträge in der blockchain:1 Inhalt der BlockChain: [ { "hash": "d6d45f5bdc7549010eb658ba1d9bd83308f03bdead9e1f548042c8ce6beba5fb", "previousHash": "0", "timeStamp": 1559052543992, "data": "Data 1" } ] Ergänze Block 2 Anzahl Einträge in der blockchain:2 Inhalt der BlockChain: [ { "hash": "d6d45f5bdc7549010eb658ba1d9bd83308f03bdead9e1f548042c8ce6beba5fb", "previousHash": "0", "timeStamp": 1559052543992, "data": "Data 1" }, { "hash": "ca56915e12b9c5374ae2c069b960b10e2b5af56a86cfe4dee6f1896008c771a2", "previousHash": "d6d45f5bdc7549010eb658ba1d9bd83308f03bdead9e1f548042c8ce6beba5fb", "timeStamp": 1559052544226, "data": "Data 2" } ] |
Der erste Datenblock („genesis block“) hat natürlich keinen Vorgänger, daher steht dort unverändert eine „0“, aber die laufende Nummer ist nun nicht „1“ sondern der errechnete Hashwert (in meinem Beispiel „d6d45f5bdc7549010eb658ba1d9bd83308f03bdead9e1f548042c8ce6beba5fb“). Der zweite Datenblock enthält diesen Wert als Vorgänger-Hash und einen neuen, eigenen Hashwert.
Natürlich könnt Ihr nun entgegenhalten, dass die Berechnung eines SHA256-Hashwertes kein Problem darstellt und eine nachträgliche Änderung doch auch recht einfach machbar ist, aber genau an dieser Stelle hat der Erfinder des Konzeptes eine Schwierigkeitsstufe eingebaut. Dieses führt dazu, dass die Berechnung des Hashwertes weitaus komplexer ist und eine größere nachträgliche Änderung zu viel Zeit benötigt – aber dazu später mehr. Weiter geht es mit Teil 3: I03 Gültigkeit der Blockchain.
Alle Quellcodes zur Blockchain findet Ihr zum Download in meinem Github-Repository, welches Ihr über diesen Link erreicht: https://github.com/java-crypto/I-Blockchain. Alle Programme sind sowohl unter Java 8 als auch unter Java 11 lauffähig.
Die Lizenz zum obigen Beispiel findet Ihr auf der eigenen Lizenz-Seite.
Letzte Aktualisierung: 28.05.2019