I was looking for information on signing Unreal’s Pak files and couldn’t find a concise description of the steps required and information needed. Now that I have it solved, I’m making it available here.
For reference we are on version 4.17 of Unreal.
Background
Epic uses 128 bit RSA keys for signing their Pak files and 128 bit AES for encryption. The keys are added to the *Encryption.ini files for your project (like DefaultEncryption.ini) found in your <project>/Config directory.
For example, Shooter Game (in the Unreal Engine samples) has:
[Core.Encryption] rsa.privateexp=0x00001ba1f34768c63eb83190c79732e1 rsa.modulus=0x00001ba1f34768c63fbf623ca6273ccf rsa.publicexp=0x000003f29077ea6576ac995dd35ebe21 aes.key=e3VqgSMhuaPw75fm0PdGZCN3ASwpVOk5Ij7iLf8VOEdqGL6aw05JeX0RHMgBvypd
Once these are available you also need a few extra options to turn it on (possibly in the same file or the platform specific versions):
[Core.Encryption] EncryptPak=True SignPak=True
Generating these keys can be done with UnrealPak but it takes an extraordinary amount of time (I had it run over night on a 48 core machine and it had yet to finish). There is a faster way.
Because we generate diffs of our Pak files for faster downloads we have EncryptPak set to false to ensure we get good diffs.
Note these values are embedded into the binary by the UnrealBuildTool when compiling the client and server so what is generated by the UnrealPak tool MUST match the binaries you build.
Generate Keys
There is an easy way to generate the RSA keys however and the method is described at https://blog.shines.me.uk/generating-rsa-public-modulus-public-exponent-private-exponent-as-hexdecimals/ but I’ll recreate it here for reference with values for our specific problem.
The tool used is OpenSSL.exe and is in the Unreal Engine depot/repository.
- Generate the RSA keys with:
-
Engine\Binaries\DotNET\IOS\openssl.exe genrsa -out private.pem 128
-
- Get the text output of the RSA keys:
-
Engine\Binaries\DotNET\IOS\openssl.exe asn1parse < private.pem
-
- This generates output like:
-
0:d=0 hl=2 l= 98 cons: SEQUENCE 2:d=1 hl=2 l= 1 prim: INTEGER :00 5:d=1 hl=2 l= 17 prim: INTEGER :E81F2D386E6E6D1866CDA3BDC3FC1C49 24:d=1 hl=2 l= 3 prim: INTEGER :010001 29:d=1 hl=2 l= 16 prim: INTEGER :74C902CA6A9D3A5B60469D0FA7CEDF91 47:d=1 hl=2 l= 9 prim: INTEGER :F685403DD05C42C5 58:d=1 hl=2 l= 9 prim: INTEGER :F10C2F3F19BFBBB5 69:d=1 hl=2 l= 9 prim: INTEGER :8AB7E4B463E0E6B9 80:d=1 hl=2 l= 8 prim: INTEGER :445592F34D86685D 90:d=1 hl=2 l= 8 prim: INTEGER :7C4BC4D20A5642ED
-
- The modulus is entry 5:
-
5:d=1 hl=2 l= 17 prim: INTEGER :E81F2D386E6E6D1866CDA3BDC3FC1C49
-
- The public exponent is entry 24 (and will need to be pre-padded with zeroes to 32 characters to be parsed correctly):
-
24:d=1 hl=2 l= 3 prim: INTEGER :010001
-
- The private exponent is entry 29:
-
29:d=1 hl=2 l= 16 prim: INTEGER :74C902CA6A9D3A5B60469D0FA7CEDF91
-
- These values fill the fields in the *Encryption.ini.
You can automate this and make it part of the build process too so the keys are rotated given that the keys are relatively small and potentially easily factorable (but may cause severe issues with Downloadable Content if you are planning that instead).
You can also add two other options to your *Game.ini:
[/Script/UnrealEd.ProjectPackagingSettings] bEncryptIniFiles=True bEncryptPakIndex=True