[JAVA] How to sign a Minecraft MOD

Introduction

When a Minecraft mod is loaded, a message may be logged to the effect that the mod's JAR file is unsigned. Even if it is unsigned, it does not affect the operation of the MOD, but for those who want to suppress the message log, I will describe the signing procedure.

Tools you need

Let's make a certificate

You will need a certificate to sign. You can generate it with OpenSSL or the Windows SDK makecert.exe, or apply to a certificate authority to issue a code signing certificate, but the PKCS12 format file obtained in this way is Yes, if you know the fingerprint value, skip to the MOD source code description. If you are unsure, skip to Confirm Fingerprint.

Try to create with JDK tools

This section describes the procedure for creating a certificate using the JDK tools. It is a so-called "Oreore certificate" that is not issued by a certificate authority, but it seems that there is no problem for Minecraft Forge.

Run the generation tool

python


$ keytool -genkeypair -storetype pkcs12 -keystore <FILENAME>.p12 -alias <FRIENDLYNAME> -keyalg ec -keysize 384 -validity 3650

-- -storetype is the certificate file format Specify pkcs12 to output in PKCS12, which is a more general format. If nothing is specified, it will be in JKS format, but a warning will be output after the key is generated. Also, be sure to set it to pkcs12 here as it will need to be processed by OpenSSL later. ---keystore specifies the name of the file where the created certificate will be saved ---alias is the base name of the signature file added to the JAR file It is represented as a friendly name in PKCS12 format. ---keyalg is a signature algorithm You can specify rsa or ʻec. ---keysizeis the key length The value that can be specified depends on the algorithm. In the case of-keyalg rsa, it will be a multiplier of 2 such as 2048or4096. In the case of -keyalg ec, it will be either 256, 384, or 521. --validityis the number of expiration days calculated from the creation date For 10 years, it will be3650`.

Specify password

When you run the command, you will first be prompted for the password. If you want to use the build.gradle task to sign, it's a good idea to use a string that you can commit to. In this case, the certificate file should never be published.

Input of various information

Next, set the common name of the certificate, which consists of multiple fields. I will explain in the order in which they are displayed.

  1. First and last name It can be a nickname or a Twitter account name.

When you have finished entering the country code, you will be asked [No]:. This is a question that doesn't make sense, but just enter y. Otherwise, you will have to start over.

Specify password

You will be asked for the password at the end, but if it is the same as the first password, just press the Enter key.

Check if the PKCS12 format contains a friendly name

When using the above keytool, the friendly name is included as the character string specified by -alias, but when issued by a certificate authority or generated by OpenSSL, the friendly name is not set. There is. This procedure can also be applied to change PKCS12 passwords.

Check friendly name

Run the following command and it's okay if you have a friendlyName under Bag Attributes.

python


$ openssl pkcs12 -in <FILENAME>.p12 -info -nokeys

Set a friendly name in PKCS12 format

If the friendly name is not set, add it.

① Backup

python


$ mv <FILENAME>.p12 <FILENAME>.p12.bak

② Take out the certificate and key from PKCS12

python


$ openssl pkcs12 -in <FILENAME>.p12.bak -info -nodes -out <FILENAME>.txt

③ Generate PKCS12 while setting a friendly name from the extracted certificate and key

python


$ openssl pkcs12 -export -in <FILENAME>.txt -name <FRIENDLYNAME> -out <FILENAME>.p12

Please note that the password must be at least 6 characters. This is a specification of jarsigner, and passwords that do not meet this will result in an error.

④ Clean up

python


$ rm <FILENAME>.txt

Examine the fingerprint value

If you want to publish a Minecraft MOD JAR file with a signature, you need the fingerprint value. A fingerprint is a value obtained by processing the data with a hash function when the certificate is expressed in binary data (ASN-1 format). Since the same fingerprint value can be obtained from the same certificate, the value examined here can be used as long as it is not recreated due to expiration. Minecraft Forge requires the value of the fingerprint in the SHA-1 hash algorithm.

Use OpenSSL

python


$ openssl pkcs12 -in <FILENAME>.p12 -info -nokeys|openssl x509 -fingerprint -noout

When executed, after entering the password, the fingerprint value will be output in hexadecimal notation separated by ":".

Make the fingerprint value a string described by MOD

After removing the ":" from this notation and connecting it, rewrite the uppercase letters to lowercase letters. This is the value of the fingerprint described in the mod.

Let's write in the source code of MOD

Add certificateFingerprint to the @ Mod annotation, and then write the fingerprint value as a string.

HogeMod.java


@Mod(modid = "hogemod",
    /*... Omitted ...*/
    certificateFingerprint = "Fingerprint value")
public class HogeMod {
/*... Omitted ...*/
}

What to do when signatures do not match

Some are not required, but are called when the signatures of Forge's event handlers do not match. As with FMLPreInitializationEvent and FMLInitializationEvent, declare a method with an argument of FMLFingerprintViolationEvent using the @ Mod.EventHandler annotation.

HogeMod.java


@Mod.EventHandler
public void badSignature(FMLFingerprintViolationEvent event)
{
    System.err.println("Signature mismatch!Not the original distribution file!");
}

After finishing the description, generate a JAR file with gradle.

Sign the JAR file

There are two ways to do the signing process, one is to execute the command and the other is to do it with gradle.

Sign with command

python


$ jarsigner -sigalg SHA256withECDSA -digestalg SHA-256 -tsa http://timestamp.digicert.com -keystore <FILENAME>.p12 <JARFILE> <FRIENDLYNAME>

---sigalg is a signature algorithm If you want to use the elliptic curve DSA, use SHA256withECDSA. ---digestalg is a hash algorithm Specify the same hash as -sigalg. In this case it will be SHA-256. ---tsa is the URL of the timestamp server You can sign without it, but the signature will be invalid when the certificate expires. There are various types of time stamp servers. This is the server that returns the time stamp signature with SHA-256. http://sha256timestamp.ws.symantec.com/sha256/timestamp

The algorithm used for signing and hashing can be anything that Java supports. https://docs.oracle.com/javase/jp/9/docs/specs/security/standard-names.html You can select -sigalg from the Signature algorithm here and -digestalg from the MessageDigest algorithm here.

You will be asked for a password, so specify the correct password to complete the signature.

Sign with Gradle

Add the following code to the end of build.gradle. Each argument passed to ʻant.signjaris the same asjarsigner` in the previous section.

build.gradle


task signJar<<{
 ant.signjar(
  jar:jar.archivePath,
  alias:"<FRIENDLYNAME>",
  keystore:"<FILENAME>.p12",
  storepass:"<PASSWORD>",
  sigalg:"SHA256withECDSA",
  digestalg:"SHA-256",
  tsaurl:"http://timestamp.digicert.com"
 )
}

signJar.dependsOn reobfJar
assemble.dependsOn signJar

When you run a build using this build.gradle, a signed JAR file will be generated.

Let's check the operation

Place the generated signed JAR file in the mods folder and launch Minecraft with Forge installed. When you reach the title screen, open logs \ debug.log, which is in the same hierarchy as ʻoptions.txt`.

If the signature is recognized successfully, such a wording will appear.

debug.log


[HH:MM:SS] [main/DEBUG] [FML]: Mod signature data
[HH:MM:SS] [main/DEBUG] [FML]:  	Valid Signatures:
... Omitted ...
[HH:MM:SS] [main/DEBUG] [FML]: 		(Fingerprint value) <MOD ID>	(<MOD name>	<MOD version>)	<JAR file name>
... Omitted ...

Recommended Posts

How to sign a Minecraft MOD
How to write a core mod in Minecraft Forge 1.15.2
How to leave a comment
How to insert a video
How to create a method
How to make a mod for Slay the Spire
How to add columns to a table
How to make a Java container
How to make a JDBC driver
[Java] How to create a folder
How to write a ternary operator
[Swift] How to send a notification
How to make a splash screen
How to make a Jenkins plugin
How to make a Maven project
Minecraft Modding [1.12] How to attach a special render for Item
How to make a Java array
[Xcode] How to add a README.md file
How to execute a contract using web3j
How to sort a List using Comparator
How to make a Java calendar Summary
A memorandum on how to use Eclipse
How to redo a deployment on Heroku
[Basic] How to write a Dockerfile Self-learning ②
How to add a new hash / array
[Introduction to Java] How to write a Java program
How to create a Maven repository for 2020
How to make a Discord bot (Java)
How to print a Java Word document
[Swift5] How to create a splash screen
[rails] How to create a partial template
How to publish a library in jCenter
[SpringBoot] How to write a controller test
How to deploy
Rails: How to write a rake task nicely
How to create a database for H2 Database anywhere
[Rails] How to write when making a subquery
How to deploy a container on AWS Lambda
[Rails] How to create a graph using lazy_high_charts
[Android] How to convert a character string to resourceId
How to get a heapdump from a Docker container
How to display a web page in Java
How to delete a controller etc. using a command
[Ethereum] How to execute a contract using web3j-Part 2-
How to create pagination for a "kaminari" array
How to create a class that inherits class information
How to convert a solidity contract to a Java contract class
[Java] Let's create a mod for Minecraft 1.14.4 [Introduction]
How to run a djUnit task in Ant
How to add a classpath in Spring Boot
How to create a theme in Liferay 7 / DXP
How to make a lightweight JRE for distribution
[Java] Let's create a mod for Minecraft 1.16.1 [Introduction]
[1st] How to create a Spring-MVC framework project
How to implement a like feature in Rails
How to easily create a pull-down in Rails
How to generate a primary key using @GeneratedValue
[Rails] How to create a Twitter share button
[Ruby] How to generate a random alphabet string
[Java] Let's create a mod for Minecraft 1.14.4 [99. Mod output]
How to make a follow function in Rails