This article belongs to H Verify external signature in Tink and is part 2.
Just for the purpose of a self-test we are going to verify the generated datafiles (see H Tink Generate an ECDSA signature) in the „classic“ way with JCE.
The programm loads the 3 datafiles (e.g. ecdsa_classic_data_256.txt):
1 2 3 4 |
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvtWc7kyPMczkBmHrCYkTotPByLoB6nhPS0tEziRW7BdIG/enrlV3d+A8S6e60IrQ4FpfZ9JiYd2FEXbYaBTwMw== VGhpcyBpcyB0aGUgbWVzc2FnZQ== MEQCICuV/9WMzYr8wnvCJc5tYPiF1WQbuy+zbMYg81isixC/AiBtqswjfn0ypc3rduK8gH949B09hyEYvvO0SLTBsrcZ/g== This file contains data in base64-format: publicKey, message, signature. Number in filename is keylength. |
After that it decodes the data back from Base64-strings to byte arrays, recodes the Public Key and verifies the message with the signature.
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 |
package tinkExternalSignatureVerification; /* * 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. * Lizenttext/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): 18.11.2019 * Funktion: überprüft eine ecdsa-signatur mittels jce * Function: verifies an ecdsa-signature with jce * * 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 ! * */ import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; public class VerifyEcdsaClassicSignature { static String pubKeyString = ""; static String messageString = ""; static String signatureString = ""; public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, InvalidKeyException, SignatureException { System.out.println("Verify a ECDSA-signed message"); String filenameTemplate = "ecdsa_classic_data_"; String filename; byte[] message = null; PublicKey pubKey; byte[] pubKeyByte = null; byte[] signature = null; String ecdsaHashtype = ""; boolean signatureVerification = false; int[] keylength = new int[] { 256, 384, 521 }; // iterate through keylength for (int myKeylength : keylength) { filename = filenameTemplate + String.valueOf(myKeylength) + ".txt"; pubKeyString = ""; messageString = ""; signatureString = ""; // load data switch (myKeylength) { case 256: { loadData(filename); ecdsaHashtype = "SHA256withECDSA"; break; } case 384: { loadData(filename); ecdsaHashtype = "SHA512withECDSA"; break; } case 521: { loadData(filename); ecdsaHashtype = "SHA512withECDSA"; break; } default: { System.out.println("Error - signature keylength not supported"); System.exit(0); } } // convert data from base64 to byte[] pubKeyByte = Base64.getDecoder().decode(pubKeyString); message = Base64.getDecoder().decode(messageString); signature = Base64.getDecoder().decode(signatureString); // rebuild publicKey KeyFactory keyFactory = KeyFactory.getInstance("EC"); X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pubKeyByte); pubKey = keyFactory.generatePublic(publicKeySpec); // verify signature signatureVerification = verifySignature(pubKey, ecdsaHashtype, message, signature); System.out.println("Data loaded from:" + filename + " The message is:" + new String(message, "UTF-8")); System.out.println("The provided signature is correct ?:" + signatureVerification); } } public static void loadData(String filenameLoad) throws IOException { BufferedReader reader = new BufferedReader(new FileReader(filenameLoad)); pubKeyString = reader.readLine(); messageString = reader.readLine(); signatureString = reader.readLine(); reader.close(); } public static Boolean verifySignature(PublicKey publicKey, String ecdsaHashtype, byte[] messageByte, byte[] signatureByte) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { Signature publicSignature = Signature.getInstance(ecdsaHashtype); publicSignature.initVerify(publicKey); publicSignature.update(messageByte); return publicSignature.verify(signatureByte); } } |
This is the output on console:
1 2 3 4 5 6 7 |
Verify a ECDSA-signed message Data loaded from:ecdsa_classic_data_256.txt The message is:This is the message The provided signature is correct ?:true Data loaded from:ecdsa_classic_data_384.txt The message is:This is the message The provided signature is correct ?:true Data loaded from:ecdsa_classic_data_521.txt The message is:This is the message The provided signature is correct ?:true |
The classic part is working as expected.
All sourcecodes to this solution are available in my Github-Archive with this link: https://github.com/java-crypto/H-Google-Tink. All programs run with Java 8 and Java 11.
The licence (or better unlicence) to my solution is available here: Lizenz-Seite.
Last edit: 18.11.2019