Bei einem Einsatz von Electrum im echten Mainnet solltet Ihr auf jeden Fall die Software auf Veränderungen prüfen. Der Hintergrund ist sehr einfach – wir reden hier von echtem Geld und wenn ich es schaffe, eine modifizierte Version einer Geldbörsen-Software zu verteilen, dann kann ich super einfach die in den Wallets gespeicherten Bitcoins für eigene Zwecke nutzen. Was hält „die bösen Buben“ denn davon ab, z.B. den geheimen Seed des Wallets über die bestehende Internetverbindung „nach Hause“ zu senden? Danach dauert es nur noch ein paar Augenblicke und die Bitcoins hat nun jemand ganz anderes…
Selbstverständlich gibt es für diesen Zweck eine „offizielle“ Lösung (für Windows „Gpg4win“) – hier ist ein Ausschnitt aus der Electrum Download-Seite:
How to verify GPG signatures
GPG signatures are a proof that distributed files have been signed by the owner of the signing key. For example, if this website was compromised and the original Electrum files had been replaced, signature verification would fail, because the attacker would not be able to create valid signatures. (Note that an attacker would be able to create valid hashes, this is why we do not publish hashes of our binaries here, it does not bring any security).
In order to be able to verify GPG signatures, you need to import the public key of the signer. Electrum binaries are signed with ThomasV’s public key. On Linux, you can import that key using the following command: gpg --import ThomasV.asc
. Here are tutorials for Windows and MacOS. When you import a key, you should check its fingerprint using independent sources, such as here, or use the Web of Trust.
Ich biete Euch nachfolgende eine Lösung unter Java an, für die die Krypto-Bibliothek „Bouncy Castle“ einbinden müsst. Die beiden notwendigen Bibliotheken „bcprov-jdk15on-164.jar“ und „bcpg-jdk15on-164.jar“ sind in meinem Github-Archiv bereits im Ordner „libs“ für Euch gespeichert.
Den Download und die Einrichtung von Electrum habe ich Euch auf der separaten Seite Bitcoin Wallet Software Electrum bereits gezeigt. Auf der Downloadseite https://electrum.org/#download findet Ihr nicht nur die Software, sondern auch die elektronische Signatur zum Download (auf der rechten Seite einfach auf „signature“ klicken und die Datei herunterladen). Beide Dateien haben die Versionsnummer in ihrem Dateinamen: zum Zeitpunkt der Artikelerstellung war es die Versionsnummer 3.3.8, daher lautet der Name der (portablen Windows) ausführbaren Datei „electrum-3.3.8-portable.exe“ und der Name der Signaturdatei „electrum-3.3.8-portable.exe.asc“.
Um an den öffentlichen Schlüssel („Public Key“) des Unterzeichners („Signierer“) heranzukommen klickt Ihr einfach die nachstehende Internetadresse an () und bekommt eine nackte Textseite zu sehen, die Ihr einfach auf der Festplatte als reine Textdatei abspeichert: „https://raw.githubusercontent.com/spesmilo/electrum/master/pubkeys/ThomasV.asc„. Hinweis: im obigen Ausschnitt aus der Downloadseite findet Ihr den Absatz „Electrum binaries are signed with ThomasV’s public key“ – dort ist der Link ebenfalls vorhanden. Ich empfehle, die neue Datei zum Beispiel „electrum_3_3_8_pgp_publickey.txt“ zu nennen.
Alle drei Dateien gehören in das Wurzelverzeichnis Eurer Java-Entwicklungsumgebung und im Programmcode solltet Ihr die Dateinamen passend zu den aktuellen Namen anpassen.
So sieht die aktuelle Signatur für Electrum Windows 3.3.8 portable aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEZpTY3nvo7lYxvtlQK9WCS3+UcOYFAl0nRwYACgkQK9WCS3+U cObkPQ/9FbdGhVsIG/SxyRXCIxSP/DnA5pNpbSCezACMSPm/suKahD6ZbpIytlZk VRU1ZZaG3mSGv7FLCGdGar7hV3n7pdy1JtmEQSuVeyIFfZ3mcnjMB8KSx6mty3Re 1apFHrH2/6XD4for4Ca970+gbFULoYy6TdB8BBXc33LqA7yMfw/eof4zF+q99Rve WPrtw8E8+t8R4eUyKNii6Ws0ry1/hkj0ipphQAC85ELPajLNIWycam8hrwPbjz8J JvB9LtKMMAxzwCxvy8rEl3+ms8a9e6jZ6DvQPInq75QHzbHsBvCdhPMkFQwTtBA8 tvS89JEi7SDZiSl7IJPDgO8tt64GqeNxs1exT9bVq/4qqr6vjrYYhVEUJBwHErJr 5VUCjTVoqji0rnb9dKbQlZ774FrNCwvpyzbi/zkJaYyfnCdtpH4o/6Z6aPw7cra1 C/SQR7WQso2k7EKLiNPqoeB3zJXiXbioaXtVbW66w6Vo1KqEacR1Z3gTZw5K1Smj DPiM0gvDCrOqCIv13BG3t5g+Jlgn1lu2QOHDMB0/GZypi8j9NYDy7mPcjAFz1EPR 7FPZceXfufHqWtLDeYJcCVJ5p/ly4W3Y9HmRdGGN0OEutDJ/z6Un9ej5FUeSgrXi V55bhIa8WiOPv5px6x/T8108me6NefonEM2+GN1ihsdfMH0HCU0= =i9XE -----END PGP SIGNATURE----- |
Der Public Key des Entwicklers ist etwas länger:
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 |
-----BEGIN PGP PUBLIC KEY BLOCK----- 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 =sUYl -----END PGP PUBLIC KEY BLOCK----- |
Bei dem Programm handelt es sich um ein Beispiel von den Entwicklern von Bouncy Castle, welches ich ein ganz klein wenig verändert habe (z.B. feste Dateinamen). Bitte beachtet, das die Beispielprogramme von Bouncy Castle unter der MIT-Lizenz stehen.
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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
/* * Herkunft/Origin: http://javacrypto.bplaced.net/ * Programmierer/Programmer: Bouncy Castle / Michael Fehr * Copyright/Copyright: Bouncy Castle * Lizenttext/Licence: MIT-License * https://github.com/java-crypto/Bitcoin/blob/master/Bitcoin%20Wallet%20Software%20Electrum%20Verification/LICENCE * getestet mit/tested with: Java Runtime Environment 11.0.5 x64 * verwendete IDE/used IDE: intelliJ IDEA 2019.3.1 * Datum/Date (dd.mm.jjjj): 26.02.2020 * Funktion: verifiziert eine PGP-signierte Datei * Function: verificates a pgp-signed file * * 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 ! * * Sie benötigen die nachfolgenden Bibliotheken (alle im Github-Archiv im Unterordner "libs") * You need the following libraries (see my Github-repository in subfolder "libs") * Bouncy Castle: bcprov-jdk15on-164.jar, bcpg-jdk15on-164.jar * my Github-Repository: https://github.com/java-crypto/PGP-Encryption-and-Signature * libs in my Github-Repo: https://github.com/java-crypto/PGP-Encryption-and-Signature/tree/master/libs * */ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.GeneralSecurityException; import java.security.Security; import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.bcpg.BCPGOutputStream; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.PGPCompressedData; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPrivateKey; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureGenerator; import org.bouncycastle.openpgp.PGPSignatureList; import org.bouncycastle.openpgp.PGPUtil; import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory; import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; /** * A simple utility class that creates seperate signatures for files and verifies them. * <p> * To sign a file: DetachedSignatureProcessor -s [-a] fileName secretKey passPhrase.<br> * If -a is specified the output file will be "ascii-armored". * <p> * To decrypt: DetachedSignatureProcessor -v fileName signatureFile publicKeyFile. * <p> * Note: this example will silently overwrite files. * It also expects that a single pass phrase * will have been used. */ public class DetachedSignatureProcessor { private static void verifySignature( String fileName, String inputFileName, String keyFileName) throws GeneralSecurityException, IOException, PGPException { InputStream in = new BufferedInputStream(new FileInputStream(inputFileName)); InputStream keyIn = new BufferedInputStream(new FileInputStream(keyFileName)); verifySignature(fileName, in, keyIn); keyIn.close(); in.close(); } /* * verify the signature in in against the file fileName. */ private static void verifySignature( String fileName, InputStream in, InputStream keyIn) throws GeneralSecurityException, IOException, PGPException { in = PGPUtil.getDecoderStream(in); JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(in); PGPSignatureList p3; Object o = pgpFact.nextObject(); if (o instanceof PGPCompressedData) { PGPCompressedData c1 = (PGPCompressedData) o; pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); p3 = (PGPSignatureList) pgpFact.nextObject(); } else { p3 = (PGPSignatureList) o; } PGPPublicKeyRingCollection pgpPubRingCollection = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator()); InputStream dIn = new BufferedInputStream(new FileInputStream(fileName)); PGPSignature sig = p3.get(0); PGPPublicKey key = pgpPubRingCollection.getPublicKey(sig.getKeyID()); sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), key); int ch; while ((ch = dIn.read()) >= 0) { sig.update((byte) ch); } dIn.close(); if (sig.verify()) { System.out.println("signature verified."); } else { System.out.println("signature verification failed."); } } private static void createSignature( String inputFileName, String keyFileName, String outputFileName, char[] pass, boolean armor) throws GeneralSecurityException, IOException, PGPException { InputStream keyIn = new BufferedInputStream(new FileInputStream(keyFileName)); OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFileName)); createSignature(inputFileName, keyIn, out, pass, armor); out.close(); keyIn.close(); } private static void createSignature( String fileName, InputStream keyIn, OutputStream out, char[] pass, boolean armor) throws GeneralSecurityException, IOException, PGPException { if (armor) { out = new ArmoredOutputStream(out); } PGPSecretKey pgpSec = PGPExampleUtil.readSecretKey(keyIn); PGPPrivateKey pgpPrivKey = pgpSec.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass)); PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1).setProvider("BC")); sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); BCPGOutputStream bOut = new BCPGOutputStream(out); InputStream fIn = new BufferedInputStream(new FileInputStream(fileName)); int ch; while ((ch = fIn.read()) >= 0) { sGen.update((byte) ch); } fIn.close(); sGen.generate().encode(bOut); if (armor) { out.close(); } } public static void main(String[] args) throws Exception { Security.addProvider(new BouncyCastleProvider()); System.out.println("Bitcoin Verify Electrum Software Download"); String filenameElectrumFile = "electrum-3.3.8-portable.exe"; String filenameSignatureFile = "electrum-3.3.8-portable.exe.asc"; String filenamePublicKeyFile = "electrum_3_3_8_pgp_publickey.txt"; System.out.println("\nDas Programm überprüft die Integrität der Software " + filenameElectrumFile + "\nanhand der Signaturdatei " + filenameSignatureFile + "\nmit dem Public Key der Software-Entwickler: " + filenamePublicKeyFile); System.out.println("\nSie erhalten die Electrum Software hier: https://electrum.org/#download"); System.out.println("\nDie Signatur finden Sie auf der selben Seite (am rechten Rand 'signature')"); System.out.println("\nDen PublicKey der Entwickler finden Sie auf dieser Seite: " + "\nhttps://raw.githubusercontent.com/spesmilo/electrum/master/pubkeys/ThomasV.asc"); System.out.println("\nSpeichern Sie diese Seite als Textdatei ab und nennen diese " + filenamePublicKeyFile); System.out.println("\nAls Ausgabe erhalten Sie vom Programm entweder" + "\n 'signature verified' = Die Signatur wurde bestätigt oder" + "\n 'signature verification failed' = Die Signatur stimmt NICHT überein - Sie sollten diese Software NICHT benutzen !\n"); verifySignature(filenameElectrumFile, filenameSignatureFile, filenamePublicKeyFile); /* Original routines // Hinweis: org.bouncycastle.openpgp.PGPException: checksum mismatch at 0 of 20 = falsches passwort System.err.println("usage: DetachedSignatureProcessor [-s [-a] file keyfile passPhrase]|[-v file sigFile keyFile]"); if (args[0].equals("-s")) { if (args[1].equals("-a")) { createSignature(args[2], args[3], args[2] + ".asc", args[4].toCharArray(), true); } else { createSignature(args[1], args[2], args[1] + ".bpg", args[3].toCharArray(), false); } } else if (args[0].equals("-v")) { verifySignature(args[1], args[2], args[3]); } else { System.err.println("usage: DetachedSignatureProcessor [-s [-a] file keyfile passPhrase]|[-v file sigFile keyFile]"); } */ } } |
und die dazugehörende Utility-Routinen:
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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
/* * Herkunft/Origin: http://javacrypto.bplaced.net/ * Programmierer/Programmer: Bouncy Castle / Michael Fehr * Copyright/Copyright: Bouncy Castle * Lizenttext/Licence: MIT-License * https://github.com/java-crypto/Bitcoin/blob/master/Bitcoin%20Wallet%20Software%20Electrum%20Verification/LICENCE * getestet mit/tested with: Java Runtime Environment 11.0.5 x64 * verwendete IDE/used IDE: intelliJ IDEA 2019.3.1 * Datum/Date (dd.mm.jjjj): 26.02.2020 * Funktion: verifiziert eine PGP-signierte Datei * Function: verificates a pgp-signed file * * 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 ! * * Sie benötigen die nachfolgenden Bibliotheken (alle im Github-Archiv im Unterordner "libs") * You need the following libraries (see my Github-repository in subfolder "libs") * Bouncy Castle: bcprov-jdk15on-164.jar, bcpg-jdk15on-164.jar * my Github-Repository: https://github.com/java-crypto/PGP-Encryption-and-Signature * libs in my Github-Repo: https://github.com/java-crypto/PGP-Encryption-and-Signature/tree/master/libs * */ import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.security.NoSuchProviderException; import java.util.Iterator; import org.bouncycastle.openpgp.PGPCompressedDataGenerator; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPLiteralData; import org.bouncycastle.openpgp.PGPPrivateKey; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.bouncycastle.openpgp.PGPUtil; import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; class PGPExampleUtil { static byte[] compressFile(String fileName, int algorithm) throws IOException { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(algorithm); PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName)); comData.close(); return bOut.toByteArray(); } /** * Search a secret key ring collection for a secret key corresponding to keyID if it * exists. * * @param pgpSec a secret key ring collection. * @param keyID keyID we want. * @param pass passphrase to decrypt secret key with. * @return the private key. * @throws PGPException * @throws NoSuchProviderException */ static PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass) throws PGPException, NoSuchProviderException { PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID); if (pgpSecKey == null) { return null; } return pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass)); } static PGPPublicKey readPublicKey(String fileName) throws IOException, PGPException { InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName)); PGPPublicKey pubKey = readPublicKey(keyIn); keyIn.close(); return pubKey; } /** * A simple routine that opens a key ring file and loads the first available key * suitable for encryption. * * @param input data stream containing the public key data * @return the first public key found. * @throws IOException * @throws PGPException */ static PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException { PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection( PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator()); // // we just loop through the collection till we find a key suitable for encryption, in the real // world you would probably want to be a bit smarter about this. // Iterator keyRingIter = pgpPub.getKeyRings(); while (keyRingIter.hasNext()) { PGPPublicKeyRing keyRing = (PGPPublicKeyRing)keyRingIter.next(); Iterator keyIter = keyRing.getPublicKeys(); while (keyIter.hasNext()) { PGPPublicKey key = (PGPPublicKey)keyIter.next(); if (key.isEncryptionKey()) { return key; } } } throw new IllegalArgumentException("Can't find encryption key in key ring."); } static PGPSecretKey readSecretKey(String fileName) throws IOException, PGPException { InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName)); PGPSecretKey secKey = readSecretKey(keyIn); keyIn.close(); return secKey; } /** * A simple routine that opens a key ring file and loads the first available key * suitable for signature generation. * * @param input stream to read the secret key ring collection from. * @return a secret key. * @throws IOException on a problem with using the input stream. * @throws PGPException if there is an issue parsing the input stream. */ static PGPSecretKey readSecretKey(InputStream input) throws IOException, PGPException { PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection( PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator()); // // we just loop through the collection till we find a key suitable for encryption, in the real // world you would probably want to be a bit smarter about this. // Iterator keyRingIter = pgpSec.getKeyRings(); while (keyRingIter.hasNext()) { PGPSecretKeyRing keyRing = (PGPSecretKeyRing)keyRingIter.next(); Iterator keyIter = keyRing.getSecretKeys(); while (keyIter.hasNext()) { PGPSecretKey key = (PGPSecretKey)keyIter.next(); if (key.isSigningKey()) { return key; } } } throw new IllegalArgumentException("Can't find signing key in key ring."); } } |
Auf der Konsole wird die Signatur überprüft und als Ergebnis (hoffentlich) „signature verified“ ausgegeben:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Bitcoin Verify Electrum Software Download Das Programm überprüft die Integrität der Software electrum-3.3.8-portable.exe anhand der Signaturdatei electrum-3.3.8-portable.exe.asc mit dem Public Key der Software-Entwickler:electrum_3_3_8_pgp_publickey.txt Sie erhalten die Software hier: https://electrum.org/#download Die Signatur finden Sie auf der selben Seite (am rechten Rand 'signature') Den PublicKey der Entwickler finden Sie auf dieser Seite: https://raw.githubusercontent.com/spesmilo/electrum/master/pubkeys/ThomasV.asc Speichern Sie die Seite als Textdatei ab und nennen diese electrum_3_3_8_pgp_publickey.txt Als Ausgabe erhalten Sie vom Programm entweder 'signature verified' = Die Signature wurde bestätigt oder 'signature verification failed' = Die Signature stimmt nicht überein - Sie sollten diese Software nicht benutzen ! signature verified. |
Alle Quellcodes zum Bitcoin findet Ihr zum Download in meinem Github-Repository, welches Ihr über diesen Link erreicht: https://github.com/java-crypto/Bitcoin. Alle Programme sind unter Java 11 lauffähig (vermutlich auch unter Java 8) und wurden mit intelliJ IDEA entwickelt, welches für dieses Programm aber nicht notwendig ist.
Letzte Bearbeitung: 26.02.2020