Intial Commit
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.*;
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
import java.util.*;
|
||||
|
||||
/** Local Ed25519 ZBS signing; private key material is never printed or packaged. */
|
||||
public class SignZBS {
|
||||
public static void main(String[] args) throws Exception {
|
||||
if(args.length<3) throw new IllegalArgumentException("init <key-directory> <SteamID64> | sign <key-directory> <jar>");
|
||||
Path dir=Path.of(args[1]);
|
||||
Path privatePath=dir.resolve("ed25519-private.der"), publicPath=dir.resolve("ed25519-public.der");
|
||||
Path authorPath=dir.resolve("author.properties");
|
||||
if(args[0].equals("init")) {
|
||||
if(!args[2].matches("[0-9]{17}")) throw new IllegalArgumentException("Invalid SteamID64");
|
||||
Files.createDirectories(dir);
|
||||
if(Files.exists(privatePath)||Files.exists(publicPath)||Files.exists(authorPath))
|
||||
throw new IllegalStateException("Signing identity already exists; reuse it rather than replacing it.");
|
||||
KeyPair pair=KeyPairGenerator.getInstance("Ed25519").generateKeyPair();
|
||||
Files.write(privatePath,pair.getPrivate().getEncoded(),StandardOpenOption.CREATE_NEW);
|
||||
Files.write(publicPath,pair.getPublic().getEncoded(),StandardOpenOption.CREATE_NEW);
|
||||
Files.writeString(authorPath,"steamID64="+args[2]+"\n",StandardOpenOption.CREATE_NEW);
|
||||
Files.writeString(dir.resolve("public-profile-key.txt"),profileKey(pair.getPublic())+"\n",StandardOpenOption.CREATE_NEW);
|
||||
System.out.println("Created dedicated Ed25519 ZombieBuddy signing identity for SteamID64 "+args[2]+".");
|
||||
return;
|
||||
}
|
||||
if(!args[0].equals("sign")) throw new IllegalArgumentException("Unknown operation");
|
||||
Properties author=new Properties();
|
||||
try(var reader=Files.newBufferedReader(authorPath)) {author.load(reader);}
|
||||
String sid=author.getProperty("steamID64");
|
||||
if(sid==null||!sid.matches("[0-9]{17}")) throw new IllegalStateException("Invalid signing identity");
|
||||
var factory=KeyFactory.getInstance("Ed25519");
|
||||
var privateKey=factory.generatePrivate(new PKCS8EncodedKeySpec(Files.readAllBytes(privatePath)));
|
||||
var publicKey=factory.generatePublic(new X509EncodedKeySpec(Files.readAllBytes(publicPath)));
|
||||
Path jar=Path.of(args[2]);
|
||||
String sha=HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(Files.readAllBytes(jar)));
|
||||
byte[] payload=("ZBS:"+sid+":"+sha).getBytes(StandardCharsets.UTF_8);
|
||||
var signer=Signature.getInstance("Ed25519");signer.initSign(privateKey);signer.update(payload);
|
||||
byte[] signature=signer.sign();
|
||||
var verifier=Signature.getInstance("Ed25519");verifier.initVerify(publicKey);verifier.update(payload);
|
||||
if(!verifier.verify(signature)) throw new IllegalStateException("Signing key pair does not match");
|
||||
Path sidecar=Path.of(jar.toString()+".zbs");
|
||||
Files.writeString(sidecar,"ZBS\nSteamID64:"+sid+"\nSignature:"+HexFormat.of().formatHex(signature)+"\n");
|
||||
System.out.println("Signed and cryptographically verified "+jar.getFileName()+" (SteamID64 "+sid+").");
|
||||
System.out.println("SHA-256: "+sha);
|
||||
}
|
||||
private static String profileKey(PublicKey key) {
|
||||
byte[] encoded=key.getEncoded();
|
||||
byte[] prefix=HexFormat.of().parseHex("302a300506032b6570032100");
|
||||
if(encoded.length!=44||!Arrays.equals(prefix,Arrays.copyOf(encoded,12)))
|
||||
throw new IllegalStateException("Unexpected Ed25519 public key encoding");
|
||||
return "JavaModZBS:"+HexFormat.of().formatHex(Arrays.copyOfRange(encoded,12,44));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user