You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

133 lines
4.8 KiB

import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.Hashtable;
import javax.naming.directory.Attribute;
import javax.naming.directory.InitialDirContext;
import org.apache.commons.codec.binary.Base32;
public class verify {
public static String pad(String base32Str) {
switch (base32Str.length() % 8) {
case 2: return base32Str + "======";
case 4: return base32Str + "====";
case 5: return base32Str + "===";
case 7: return base32Str + "=";
}
return base32Str;
}
public static String rmPad(String base32Str) {
return base32Str.replaceAll("=", "");
}
public static String buildPEMFromDNS(String encodedKey) {
String key = encodedKey.replaceAll("\"","").replaceAll("\\\\n", "n").replaceAll("\\\\n", "\n");
if (!key.contains("-----BEGIN PUBLIC KEY-----")) {
key = "-----BEGIN PUBLIC KEY-----" + "\n" + key + "\n" + "-----END PUBLIC KEY-----\n";
}
return key;
}
public static String downloadPubKeyFromTXTRecord(String pubKeyLink) throws Exception {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
Attribute txt = new InitialDirContext(env).getAttributes(pubKeyLink, new String[] { "TXT" }).get("TXT");
return buildPEMFromDNS(txt.get(0).toString());
}
public static PrivateKey getPrivateKey() throws Exception {
String privKeyPEM = new String(Files.readAllBytes(Paths.get("keys/ecdsa_private_key8.pem")));
privKeyPEM = privKeyPEM.replaceAll("\\n", "")
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "");
PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privKeyPEM));
return KeyFactory.getInstance("EC").generatePrivate(keySpecPKCS8);
}
public static PublicKey getPublicKey(String pubKeyLink) throws Exception {
String pubKeyPEM = downloadPubKeyFromTXTRecord(pubKeyLink);
pubKeyPEM = pubKeyPEM.replaceAll("\\n", "")
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "");
X509EncodedKeySpec x509 = new X509EncodedKeySpec(Base64.getDecoder().decode(pubKeyPEM));
return KeyFactory.getInstance("EC").generatePublic(x509);
}
public static String[] parseQR(String qr) {
return qr.split(":");
}
public static boolean parseAndVerifyQR(String qr) throws Exception {
String[] qrArray = parseQR(qr);
System.out.println("Parsed QR\t" + Arrays.toString(qrArray));
String base32Signature = qrArray[3];
String pubKeyLink = qrArray[4];
String payload = qrArray[5];
byte[] payloadBytes = payload.getBytes();
byte[] signatureDER = new Base32().decode(pad(base32Signature).getBytes());
Signature s = Signature.getInstance("SHA256withECDSA");
s.initVerify(getPublicKey(pubKeyLink));
s.update(payloadBytes);
System.out.println("Payload Bytes\t" + Arrays.toString(payloadBytes));
System.out.println("Signature DER\t" + Arrays.toString(signatureDER));
boolean verified = s.verify(signatureDER);
System.out.println("");
System.out.println("Verify Payload\t" + verified);
return verified;
}
public static String signAndFormatQR(String schema, String qrtype, String version, String pubKeyLink, String payload) throws Exception {
byte[] payloadBytes = payload.getBytes();
Signature s = Signature.getInstance("SHA256withECDSA");
s.initSign(getPrivateKey());
s.update(payloadBytes);
byte[] signatureDER = s.sign();
String formattedSig = rmPad(new String(new Base32().encode(signatureDER)));
return schema + ":" + qrtype + ":" + version + ":" + formattedSig + ":" + pubKeyLink + ":" + payload;
}
public static void main( String args[]) throws Exception {
String qr = "CRED:STATUS:2:GBCAEIAHV2J6PWDSYVLI67RN55WVHIMUTKLFF5GZ4NPHPZ7ZSIJE4MP5M4BCAU6QVDHUP4RQCPXW6XJDAM54VMZ7XURUN34WFT2RWL5ETTZDNHUF:KEYS.PATHCHECK.ORG:1/BUQHHANUB4Z5KHBZTYCWMNI4RQ6CP5WFVVQCUXYHCQVY5WLDDFPA/";
System.out.println("");
System.out.println("Loading hardcoded QR");
System.out.println("");
parseAndVerifyQR(qr);
System.out.println("");
System.out.println("Resigning same payload");
System.out.println("");
String[] qrArray = parseQR(qr);
String newQR = signAndFormatQR(qrArray[0], qrArray[1], qrArray[2], qrArray[4], qrArray[5]);
System.out.println("New QR Signed\t" + newQR);
System.out.println("");
parseAndVerifyQR(newQR);
}
}