Signing a JAR
Java allows developers to sign their jar files with a signature. However, these signatures are not designed to be used as security and shouldn’t be used this way. Signatures are used as sanity checks, so that developers are able to check if they are running their own un-edited code.
Note
Once again keep in mind that this system is not intended to be a security measure. With enough malicious intend it can be circumvented.
Creating a keystore
A keystore is a private database file which holds the required information to successfully sign the jar. To sign a jar, you need both a public and a private key. The public key will be later used to check if the jar is correctly signed.
To generate a key, execute the following command and follow the instructions given by the keytool. The key should be SHA-1 encoded.
keytool -genkey -alias signFiles -keystore examplestore.jks
* The keytool
is part of the Java Development Kit and can be found in the underlying bin
directory.
* The alias signFiles
indicates that the alias should be used in future to refer to the keystore entry
* -keystore examplestore.jks
means that the keystore will be saved to the file examplestore.jks
.
Get the public key
To gather the public key required by Forge, execute the following command:
keytool -list -alias signFiles -keystore examplestore.jks
Now copy the public key and remove all colons and change all uppercase letters to lowercase to ensure
that FML can work with the key.
Checking at runtime
To allow FML to compare the keys, add the public key to the certificateFingerprint
argument in the @Mod
annotation.
When FML detects that the keys don’t match it will fire the mod-lifecycle event FMLFingerprintViolationEvent
How to
handle this key mismatch is up to the developer.
event.isDirectory()
- Returns true when the mod runs in development environment.event.getSource()
- Returns the file with the key mismatch.event.getExpectedFingerprint()
- Returns the public key.event.getFingerprints()
- Returns all public keys found.
Buildscript setup
Finally, to let Gradle sign the jar file with the generated key pair, a new task in the
buildscript build.gradle
is required.
task signJar(type: SignJar, dependsOn: reobfJar) {
inputFile = jar.archivePath
outputFile = jar.archivePath
}
build.dependsOn signJar
dependsOn: reobfJar
- This snippet of the line is important because Gradle has to sign the jar after ForgeGradle has reobfuscated the jar.jar.archivePath
- The path where the archive (jar) is constructed.build.dependsOn signJar
- This line tells Gradle that this task is part of the build task started bygradlew build
.
The following values for the signJar
task must be defined to ensure that Gradle can find the keystore and actually sign the jar.
This has to be done in the gradle.properties
file.
keyStore
- This value tells Gradle where to search for the generated keystore.alias
- The alias which was defined in the above is required in order for Gradle to sign the jar.storePass
- The password which was defined by creating the keystore is required in order for Gradle to access the file.keyPass
- The password of the key which was defined by creating the keystore is required in order for Gradle to gain access to it. This password may be the same as storePass, but can be different.