我们希望在项目中使用Tink库,以便能够在给定公共密钥的情况下验证某些传入签名。
我们拥有以下内容:
在阅读了Tink的文档之后,我们无法弄清楚如何加载公钥字符串,以便PublicKeyVerifyFactory
可以使用它。
有人做过类似的事情吗?您在网上找到任何示例可以为我们指明正确的方向吗?
答案 0 :(得分:1)
一些代码示例片段说明:
public static boolean verify(byte[] data, byte[] signature, KeysetHandle publicKeysetHandle, CIPHER_ASYMMETRIC_ALGOS algo_chosen) throws IOException, GeneralSecurityException {
TinkConfig.register();
boolean status_verification = False;
try {
PublicKeyVerify verifier = PublicKeyVerifyFactory.getPrimitive( publicKeysetHandle);
verifier.verify(signature, data);
status_verification = True;
} catch (GeneralSecurityException e) {
status_verification = False;
}
return status_verification;
}
//假设您已经具有以字节为单位的签名。
用法:
boolean status_verification = verify(data, signature, publicKeysetHandle);
if(status_verification == True){
System.out.println(“status_verification: PASS”);
} else {
System.out.println(“status_verification: FAIL”);
}
答案 1 :(得分:1)
您可以通过try
{
this.viewer.frame();
}
catch (AccessViolationException exception)
{
Console.WriteLine(exception);
}
通过公用密钥创建KeysetHandle
,然后获取它的原始内容,然后验证签名。您不需要知道KeysetHandle的私有部分就可以做到这一点,这就是首先使用非对称密钥的关键所在。
问题是,我应该导出什么才能在以后使用此CleartextKeysetHandle.read()
?
有几种方法,但是一种方法是将read()
导出为JSON格式。您可以将PublicKeysetHandle
与CleartextKeysetHandle.write()
一起导出,然后再通过JsonKeysetWriter.withOutputStream()
与KeysetHandle
将其转换回CleartextKeysetHandle.read()
。
因此,您是Bob,并且想向Alice公开您的公钥。在您的服务中,您将生成私钥,提取公钥,将其转换为JSON格式,然后以某种方式导出,例如REST端点:
鲍勃的申请
JsonKeysetReader.withBytes()
爱丽丝的申请
SignatureConfig.register();
// This is your, and only yours, private key.
KeysetHandle privateKeysetHandle =
KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P256);
// This is the public key extracted from the private key.
KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle();
ByteArrayOutputStream publicKeyStream = new ByteArrayOutputStream();
CleartextKeysetHandle.write(publicKeysetHandle,
JsonKeysetWriter.withOutputStream(publicKeyStream));
// And this is the public key in JSON format.
// You can publish this in a REST endpoint.
return publicKeyStream.toString();
在Bob的应用程序中,每次都会生成私钥。您可能希望使用相同的私钥,因此您需要存储该私钥并像Alice的应用程序一样还原它,但是使用PublicKeysetHandle代替使用PublicKeysetHandle。上面的示例只是为了展示如何将公共密钥导出为字符串格式,然后在其他应用程序中将其还原。
答案 2 :(得分:0)
Tink将公共密钥存储在protobuf中。这些天之一,我将编写一些代码,以将诸如PEM或JWK之类的通用公钥格式转换为protobuf,但在那之前,我担心您将不得不自己编写代码(并做出贡献!)。>
答案 3 :(得分:0)
我认为我的回答对于Alex来说为时已晚,但对其他人可能会有帮助。经过大量代码和密钥分析之后,我编写了一个解决方案,该解决方案使用外部生成的带有Tink密码例程的ECDSA公钥来验证外部生成的ECDSA签名。为了对此进行测试,有一个帮助程序,该程序使用常规的JCE工具生成“外部”,并将公共密钥,消息和签名保存在文本文件中(所有数据均经过Base64编码)。
我的解决方案加载了数据文件(总共有3个数据文件可以测试所有3个可用的ECDSA曲线(P256,P384和P521))。然后,它以Tink拥有的JSON格式创建了一个新的公钥文件(同样:3个文件,具有3个密钥长度)-该文件是手工制作的解决方案,重新加载密钥文件并构造一个新的签名,使其符合Tink。 >
最后,程序将验证签名正确无误。。请记住,我的源代码是“概念证明”,并未针对任何内容进行优化:-)任何有关更好编码的建议均应包含在文档中。总是要求!
在分析Tink源代码时,我看到也有“ RAW”格式,但是在Tink文档中,我找不到任何单词来使用它们:-(
您也可以在我的Github-Archive:https://github.com/java-crypto/H-Google-Tink中找到完整的源代码,并在我的网站http://javacrypto.bplaced.net/h-verify-external-signature-in-tink/上找到所有程序的更详细说明。 这些程序已通过Java 8-191和Java 11-0-1进行了测试。
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 extern erzeugte ecdsa-signatur mittels google tink
* Function: verifies an external generated ecdsa-signature with google tink
*
* 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 nachfolgenden Bibliotheken (siehe Github Archiv):
* The programm uses these external libraries (see Github Archive):
* jar-Datei/-File: tink-1.2.2.jar
* https://mvnrepository.com/artifact/com.google.crypto.tink/tink/1.2.2
* jar-Datei/-File: protobuf-java-3.10.0.jar
* https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java/3.10.0
* jar-Datei/-File: json-20190722.jar
* https://mvnrepository.com/artifact/org.json/json/20190722
*
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECPoint;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import com.google.crypto.tink.CleartextKeysetHandle;
import com.google.crypto.tink.JsonKeysetReader;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.PublicKeyVerify;
import com.google.crypto.tink.config.TinkConfig;
import com.google.crypto.tink.signature.PublicKeyVerifyFactory;
public class VerifyEcdsaTinkSignature {
static String pubKeyString = "";
static String messageString = "";
static String signatureString = "";
public static byte[] xRec = null; // x-value of recoded public key
public static byte[] yRec = null; // y-value of recoded public key
public static void main(String[] args) throws IOException, GeneralSecurityException {
System.out.println("Verify a Classic ECDSA-signed message in Google Tink");
TinkConfig.register();
String publicKeyJsonFilenameTemplate = "ecdsa_tink_publickey_";
String publicKeyJsonFilename = "";
String filenameTemplate = "ecdsa_classic_data_";
String filename;
byte[] message = null;
PublicKey pubKey;
byte[] pubKeyByte = null;
byte[] signatureClassic = null; // the signature from classic ecdsa
boolean signatureVerification = false;
int[] keylength = new int[] { 256, 384, 521 };
// iterate through keylength
for (int myKeylength : keylength) {
filename = filenameTemplate + String.valueOf(myKeylength) + ".txt";
publicKeyJsonFilename = publicKeyJsonFilenameTemplate + String.valueOf(myKeylength) + ".txt";
pubKeyString = "";
messageString = "";
signatureString = "";
// load data
switch (myKeylength) {
case 256: {
loadData(filename);
break;
}
case 384: {
loadData(filename);
break;
}
case 521: {
loadData(filename);
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);
signatureClassic = Base64.getDecoder().decode(signatureString);
// rebuild publicKey
KeyFactory keyFactory = KeyFactory.getInstance("EC");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pubKeyByte);
pubKey = keyFactory.generatePublic(publicKeySpec);
// get x + y value of public key
returnPublicKeyXY(pubKey); // writes to variables xRec and yRec
// construct a tink-style public key value for json-file
byte[] keyValueClassic = generateKeyValue(myKeylength);
String keyValueClassicString = Base64.getEncoder().encodeToString(keyValueClassic); // saved in value-field
// of json-file
// save tink public key in json-format, gets the generated primaryKeyId
int keyId = SaveJson.writeJson(publicKeyJsonFilename, keyValueClassicString);
// construct a tink-style signature
byte[] signatureTink = generateSignature(keyId, signatureClassic);
// reload the self created public key
KeysetHandle keysetHandle = CleartextKeysetHandle
.read(JsonKeysetReader.withFile(new File(publicKeyJsonFilename)));
// verify signature
signatureVerification = verifyMessage(keysetHandle, signatureTink, message);
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 String printHexBinary(byte[] bytes) {
final char[] hexArray = "0123456789ABCDEF".toCharArray();
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
// source:
// https://github.com/google/tink/blob/master/java/src/main/java/com/google/crypto/tink/subtle/EllipticCurves.java
/**
* Transforms a big integer to its minimal signed form, i.e., no extra zero byte
* at the beginning except single one when the highest bit is set.
*/
private static byte[] toMinimalSignedNumber(byte[] bs) {
// Remove zero prefixes.
int start = 0;
while (start < bs.length && bs[start] == 0) {
start++;
}
if (start == bs.length) {
start = bs.length - 1;
}
int extraZero = 0;
// If the 1st bit is not zero, add 1 zero byte.
if ((bs[start] & 0x80) == 0x80) {
// Add extra zero.
extraZero = 1;
}
byte[] res = new byte[bs.length - start + extraZero];
System.arraycopy(bs, start, res, extraZero, bs.length - start);
return res;
}
public static void returnPublicKeyXY(PublicKey pub) {
ECPublicKey key = (ECPublicKey) pub;
ECPoint ecp = key.getW();
BigInteger x = ecp.getAffineX();
BigInteger y = ecp.getAffineY();
// convert big integer to byte[]
byte[] x_array = x.toByteArray();
if (x_array[0] == 0) {
byte[] tmp = new byte[x_array.length - 1];
System.arraycopy(x_array, 1, tmp, 0, tmp.length);
x_array = tmp;
}
byte[] y_array = y.toByteArray();
if (y_array[0] == 0) {
byte[] tmp = new byte[y_array.length - 1];
System.arraycopy(y_array, 1, tmp, 0, tmp.length);
y_array = tmp;
}
// some byte[] need an additional x00 in the beginning
xRec = toMinimalSignedNumber(x_array);
yRec = toMinimalSignedNumber(y_array);
}
public static byte[] generateKeyValue(int keylength) {
// header depends on keylength
byte[] header = null;
switch (keylength) {
case 256: {
header = fromHexString("12060803100218021A"); // only for ECDSA_P256
break;
}
case 384: {
header = fromHexString("12060804100318021A"); // only for ECDSA_P384
break;
}
case 521: {
header = fromHexString("12060804100418021A"); // only for ECDSA_P521
break;
}
}
int x_length = xRec.length;
int y_length = yRec.length;
// build the value-field with public key in x-/y-notation
byte[] x_header = new byte[] { (byte) x_length };
byte[] y_preheader = fromHexString("22");
byte[] y_header = new byte[] { (byte) y_length };
// join arrays
byte[] kv = new byte[header.length + x_header.length + xRec.length + +y_preheader.length + y_header.length
+ yRec.length];
System.arraycopy(header, 0, kv, 0, header.length);
System.arraycopy(x_header, 0, kv, header.length, x_header.length);
System.arraycopy(xRec, 0, kv, (header.length + x_header.length), xRec.length);
System.arraycopy(y_preheader, 0, kv, (header.length + x_header.length + xRec.length), y_preheader.length);
System.arraycopy(y_header, 0, kv, (header.length + x_header.length + xRec.length + y_preheader.length),
y_header.length);
System.arraycopy(yRec, 0, kv,
(header.length + x_header.length + xRec.length + y_preheader.length + y_header.length), yRec.length);
return kv;
}
// this routine converts a Hex Dump String to a byte array
private static byte[] fromHexString(final String encoded) {
if ((encoded.length() % 2) != 0)
throw new IllegalArgumentException("Input string must contain an even number of characters");
final byte result[] = new byte[encoded.length() / 2];
final char enc[] = encoded.toCharArray();
for (int i = 0; i < enc.length; i += 2) {
StringBuilder curr = new StringBuilder(2);
curr.append(enc[i]).append(enc[i + 1]);
result[i / 2] = (byte) Integer.parseInt(curr.toString(), 16);
}
return result;
}
public static byte[] generateSignature(int keyId, byte[] signatureByte) {
byte[] header = fromHexString("01");
// convert keyId from int to 4-byte byte[]
byte[] keyIdBytes = ByteBuffer.allocate(4).putInt(keyId).array();
// build the signature in tink-style with keyId included
byte[] si = new byte[header.length + keyIdBytes.length + signatureByte.length];
System.arraycopy(header, 0, si, 0, header.length);
System.arraycopy(keyIdBytes, 0, si, header.length, keyIdBytes.length);
System.arraycopy(signatureByte, 0, si, (header.length + keyIdBytes.length), signatureByte.length);
return si;
}
public static boolean verifyMessage(KeysetHandle publicKeysetHandle, byte[] signature, byte[] message)
throws UnsupportedEncodingException, GeneralSecurityException {
Boolean verifiedBool = false;
PublicKeyVerify verifier = PublicKeyVerifyFactory.getPrimitive(publicKeysetHandle);
try {
verifier.verify(signature, message);
verifiedBool = true;
} catch (GeneralSecurityException e) {
verifiedBool = false;
}
return verifiedBool;
}
}
您需要此附加帮助器类来保存JSON文件:
package tinkExternalSignatureVerification;
/*
* Diese Klasse gehört zu VerifyEcdsaTinkSignature.java
* This class belongs to VerifyEcdsaTinkSignature.java
* 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>
*/
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.security.SecureRandom;
public class SaveJson {
public static int writeJson(String filename, String value) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(filename));
int keyId = newKeyId();
String str = "{";
writer.write(str + "\n");
str = " \"primaryKeyId\": " + keyId + ",";
writer.append(str + "\n");
str = " \"key\": [{";
writer.append(str + "\n");
str = " \"keyData\": {";
writer.append(str + "\n");
str = " \"typeUrl\": \"type.googleapis.com/google.crypto.tink.EcdsaPublicKey\",";
writer.append(str + "\n");
str = " \"keyMaterialType\": \"ASYMMETRIC_PUBLIC\",";
writer.append(str + "\n");
str = " \"value\": \"" + value + "\"";
writer.append(str + "\n");
str = " },";
writer.append(str + "\n");
str = " \"outputPrefixType\": \"TINK\",";
writer.append(str + "\n");
str = " \"keyId\": " + keyId + ",";
writer.append(str + "\n");
str = " \"status\": \"ENABLED\"";
writer.append(str + "\n");
str = " }]";
writer.append(str + "\n");
str = "}";
writer.append(str);
writer.close();
return keyId;
}
// routines for keyId
private static int newKeyId() {
int keyId = randPositiveInt();
keyId = randPositiveInt();
return keyId;
}
// source:
// https://github.com/google/tink/blob/08405fb55ba695b60b41f7f9ae198e5748152604/java/src/main/java/com/google/crypto/tink/KeysetManager.java
/** @return positive random int */
private static int randPositiveInt() {
SecureRandom secureRandom = new SecureRandom();
byte[] rand = new byte[4];
int result = 0;
while (result == 0) {
secureRandom.nextBytes(rand);
result = ((rand[0] & 0x7f) << 24) | ((rand[1] & 0xff) << 16) | ((rand[2] & 0xff) << 8) | (rand[3] & 0xff);
}
return result;
}
}
数据文件是由以下简短程序生成的:
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: erzeugt eine ecdsa-signatur mittels jce
* Function: generates 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.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.util.Base64;
public class GenerateEcdsaClassicSignature {
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException,
InvalidKeyException, SignatureException, IOException {
System.out.println("Generate a ECDSA Private-/PublicKey and signs a message");
byte[] message = "This is the message".getBytes("utf-8");
String messageString = "";
String filenameTemplate = "ecdsa_classic_data_";
String filename;
byte[] signature = null;
String signatureString = "";
PrivateKey privKey;
PublicKey pubKey;
String pubKeyString = "";
int[] keylength = new int[] { 256, 384, 521 };
// iterate through keylength
for (int myKeylength : keylength) {
filename = filenameTemplate + String.valueOf(myKeylength) + ".txt";
// generate keypair
KeyPair keyPair = generateEcdsaClassicKeyPair(myKeylength);
privKey = keyPair.getPrivate();
pubKey = keyPair.getPublic();
signature = null;
// sign the message
switch (myKeylength) {
case 256: {
signature = signEcdsaClassic(privKey, message, "SHA256withECDSA");
break;
}
case 384: {
signature = signEcdsaClassic(privKey, message, "SHA512withECDSA");
break;
}
case 521: {
signature = signEcdsaClassic(privKey, message, "SHA512withECDSA");
break;
}
default: {
System.out.println("Error - signature keylength not supported");
System.exit(0);
}
}
// convert data to base64
pubKeyString = Base64.getEncoder().encodeToString(pubKey.getEncoded());
messageString = Base64.getEncoder().encodeToString(message);
signatureString = Base64.getEncoder().encodeToString(signature);
// save data to file
writeData(filename, pubKeyString, messageString, signatureString);
System.out.println("Data written to:" + filename);
}
}
public static KeyPair generateEcdsaClassicKeyPair(int keylengthInt)
throws NoSuchAlgorithmException, NoSuchProviderException {
KeyPairGenerator keypairGenerator = KeyPairGenerator.getInstance("EC");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
keypairGenerator.initialize(keylengthInt, random);
return keypairGenerator.generateKeyPair();
}
public static byte[] signEcdsaClassic(PrivateKey privateKey, byte[] message, String ecdsaHashtype)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
Signature signature = Signature.getInstance(ecdsaHashtype);
signature.initSign(privateKey);
signature.update(message);
byte[] sigByte = signature.sign();
return sigByte;
}
public static void writeData(String filenameWrite, String pubKeyWrite, String messageWrite, String signatureWrite)
throws IOException {
FileWriter fw = new FileWriter(filenameWrite);
fw.write(pubKeyWrite + "\n");
fw.write(messageWrite + "\n");
fw.write(signatureWrite + "\n");
fw.write(
"This file contains data in base64-format: publicKey, message, signature. Number in filename is keylength.");
fw.flush();
fw.close();
}
}
最后-如果您想使用JCE验证数据文件,请使用以下程序:
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);
}
}