/// <summary> /// Parse crypto settings from INI file /// </summary> public static CryptoSettings ParseCryptoSettings(DirectoryReference InProjectDirectory, UnrealTargetPlatform InTargetPlatform) { CryptoSettings Settings = new CryptoSettings(); ConfigHierarchy Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, InProjectDirectory, InTargetPlatform); Ini.GetBool("PlatformCrypto", "PlatformRequiresDataCrypto", out Settings.bDataCryptoRequired); // For now, we'll just not parse any keys if data crypto is disabled for this platform. In the future, we might want to use // these keys for non-data purposes (other general purpose encryption maybe?) if (!Settings.bDataCryptoRequired) { return(Settings); } { // Start by parsing the legacy encryption.ini settings Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Encryption, InProjectDirectory, InTargetPlatform); Ini.GetBool("Core.Encryption", "SignPak", out Settings.bEnablePakSigning); string[] SigningKeyStrings = new string[3]; Ini.GetString("Core.Encryption", "rsa.privateexp", out SigningKeyStrings[0]); Ini.GetString("Core.Encryption", "rsa.modulus", out SigningKeyStrings[1]); Ini.GetString("Core.Encryption", "rsa.publicexp", out SigningKeyStrings[2]); if (String.IsNullOrEmpty(SigningKeyStrings[0]) || String.IsNullOrEmpty(SigningKeyStrings[1]) || String.IsNullOrEmpty(SigningKeyStrings[2])) { SigningKeyStrings = null; } else { Settings.SigningKey = new SigningKeyPair(); Settings.SigningKey.PrivateKey.Exponent = ParseHexStringToByteArray(SigningKeyStrings[0]); Settings.SigningKey.PrivateKey.Modulus = ParseHexStringToByteArray(SigningKeyStrings[1]); Settings.SigningKey.PublicKey.Exponent = ParseHexStringToByteArray(SigningKeyStrings[2]); Settings.SigningKey.PublicKey.Modulus = Settings.SigningKey.PrivateKey.Modulus; } Ini.GetBool("Core.Encryption", "EncryptPak", out Settings.bEnablePakIndexEncryption); Settings.bEnablePakFullAssetEncryption = false; Settings.bEnablePakUAssetEncryption = false; Settings.bEnablePakIniEncryption = Settings.bEnablePakIndexEncryption; string EncryptionKeyString; Ini.GetString("Core.Encryption", "aes.key", out EncryptionKeyString); Settings.EncryptionKey = new EncryptionKey(); Settings.EncryptionKey.Key = ParseAnsiStringToByteArray(EncryptionKeyString); } Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Crypto, InProjectDirectory, InTargetPlatform); string SectionName = "/Script/CryptoKeys.CryptoKeysSettings"; ConfigHierarchySection CryptoSection = Ini.FindSection(SectionName); // If we have new format crypto keys, read them in over the top of the legacy settings if (CryptoSection != null && CryptoSection.KeyNames.Count() > 0) { Ini.GetBool(SectionName, "bEnablePakSigning", out Settings.bEnablePakSigning); Ini.GetBool(SectionName, "bEncryptPakIniFiles", out Settings.bEnablePakIniEncryption); Ini.GetBool(SectionName, "bEncryptPakIndex", out Settings.bEnablePakIndexEncryption); Ini.GetBool(SectionName, "bEncryptUAssetFiles", out Settings.bEnablePakUAssetEncryption); Ini.GetBool(SectionName, "bEncryptAllAssetFiles", out Settings.bEnablePakFullAssetEncryption); // Parse encryption key string EncryptionKeyString; Ini.GetString(SectionName, "EncryptionKey", out EncryptionKeyString); if (!string.IsNullOrEmpty(EncryptionKeyString)) { Settings.EncryptionKey = new EncryptionKey(); Settings.EncryptionKey.Key = System.Convert.FromBase64String(EncryptionKeyString); if (Settings.EncryptionKey.Key.Length != 32) { throw new Exception("The encryption key specified in the crypto config file must be 32 bytes long!"); } } // Parse signing key string PrivateExponent, PublicExponent, Modulus; Ini.GetString(SectionName, "SigningPrivateExponent", out PrivateExponent); Ini.GetString(SectionName, "SigningModulus", out Modulus); Ini.GetString(SectionName, "SigningPublicExponent", out PublicExponent); if (!String.IsNullOrEmpty(PrivateExponent) && !String.IsNullOrEmpty(PublicExponent) && !String.IsNullOrEmpty(Modulus)) { Settings.SigningKey = new SigningKeyPair(); Settings.SigningKey.PublicKey.Exponent = System.Convert.FromBase64String(PublicExponent); Settings.SigningKey.PublicKey.Modulus = System.Convert.FromBase64String(Modulus); Settings.SigningKey.PrivateKey.Exponent = System.Convert.FromBase64String(PrivateExponent); Settings.SigningKey.PrivateKey.Modulus = Settings.SigningKey.PublicKey.Modulus; } } return(Settings); }
/// <summary> /// Parse crypto settings from INI file /// </summary> public static CryptoSettings ParseCryptoSettings(DirectoryReference InProjectDirectory, UnrealTargetPlatform InTargetPlatform) { CryptoSettings Settings = new CryptoSettings(); ConfigHierarchy Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, InProjectDirectory, InTargetPlatform); Ini.GetBool("PlatformCrypto", "PlatformRequiresDataCrypto", out Settings.bDataCryptoRequired); Ini.GetBool("PlatformCrypto", "PakSigningRequired", out Settings.PakSigningRequired); Ini.GetBool("PlatformCrypto", "PakEncryptionRequired", out Settings.PakEncryptionRequired); { // Start by parsing the legacy encryption.ini settings Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Encryption, InProjectDirectory, InTargetPlatform); Ini.GetBool("Core.Encryption", "SignPak", out Settings.bEnablePakSigning); string[] SigningKeyStrings = new string[3]; Ini.GetString("Core.Encryption", "rsa.privateexp", out SigningKeyStrings[0]); Ini.GetString("Core.Encryption", "rsa.modulus", out SigningKeyStrings[1]); Ini.GetString("Core.Encryption", "rsa.publicexp", out SigningKeyStrings[2]); if (String.IsNullOrEmpty(SigningKeyStrings[0]) || String.IsNullOrEmpty(SigningKeyStrings[1]) || String.IsNullOrEmpty(SigningKeyStrings[2])) { SigningKeyStrings = null; } else { Settings.SigningKey = new SigningKeyPair(); Settings.SigningKey.PrivateKey.Exponent = ParseHexStringToByteArray(ProcessSigningKeyInputStrings(SigningKeyStrings[0]), 64); Settings.SigningKey.PrivateKey.Modulus = ParseHexStringToByteArray(ProcessSigningKeyInputStrings(SigningKeyStrings[1]), 64); Settings.SigningKey.PublicKey.Exponent = ParseHexStringToByteArray(ProcessSigningKeyInputStrings(SigningKeyStrings[2]), 64); Settings.SigningKey.PublicKey.Modulus = Settings.SigningKey.PrivateKey.Modulus; if ((Settings.SigningKey.PrivateKey.Exponent.Length > 64) || (Settings.SigningKey.PrivateKey.Modulus.Length > 64) || (Settings.SigningKey.PublicKey.Exponent.Length > 64) || (Settings.SigningKey.PublicKey.Modulus.Length > 64)) { throw new Exception(string.Format("[{0}] Signing keys parsed from encryption.ini are too long. They must be a maximum of 64 bytes long!", InProjectDirectory)); } } Ini.GetBool("Core.Encryption", "EncryptPak", out Settings.bEnablePakIndexEncryption); Settings.bEnablePakFullAssetEncryption = false; Settings.bEnablePakUAssetEncryption = false; Settings.bEnablePakIniEncryption = Settings.bEnablePakIndexEncryption; string EncryptionKeyString; Ini.GetString("Core.Encryption", "aes.key", out EncryptionKeyString); Settings.EncryptionKey = new EncryptionKey(); if (EncryptionKeyString.Length > 0) { if (EncryptionKeyString.Length < 32) { Log.WriteLine(LogEventType.Warning, "AES key parsed from encryption.ini is too short. It must be 32 bytes, so will be padded with 0s, giving sub-optimal security!"); } else if (EncryptionKeyString.Length > 32) { Log.WriteLine(LogEventType.Warning, "AES key parsed from encryption.ini is too long. It must be 32 bytes, so will be truncated!"); } Settings.EncryptionKey.Key = ParseAnsiStringToByteArray(EncryptionKeyString, 32); } } Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Crypto, InProjectDirectory, InTargetPlatform); string SectionName = "/Script/CryptoKeys.CryptoKeysSettings"; ConfigHierarchySection CryptoSection = Ini.FindSection(SectionName); // If we have new format crypto keys, read them in over the top of the legacy settings if (CryptoSection != null && CryptoSection.KeyNames.Count() > 0) { Ini.GetBool(SectionName, "bEnablePakSigning", out Settings.bEnablePakSigning); Ini.GetBool(SectionName, "bEncryptPakIniFiles", out Settings.bEnablePakIniEncryption); Ini.GetBool(SectionName, "bEncryptPakIndex", out Settings.bEnablePakIndexEncryption); Ini.GetBool(SectionName, "bEncryptUAssetFiles", out Settings.bEnablePakUAssetEncryption); Ini.GetBool(SectionName, "bEncryptAllAssetFiles", out Settings.bEnablePakFullAssetEncryption); // Parse encryption key string EncryptionKeyString; Ini.GetString(SectionName, "EncryptionKey", out EncryptionKeyString); if (!string.IsNullOrEmpty(EncryptionKeyString)) { Settings.EncryptionKey = new EncryptionKey(); Settings.EncryptionKey.Key = System.Convert.FromBase64String(EncryptionKeyString); Settings.EncryptionKey.Guid = Guid.Empty.ToString(); Settings.EncryptionKey.Name = "Embedded"; } // Parse secondary encryption keys List <EncryptionKey> SecondaryEncryptionKeys = new List <EncryptionKey>(); List <string> SecondaryEncryptionKeyStrings; if (Ini.GetArray(SectionName, "SecondaryEncryptionKeys", out SecondaryEncryptionKeyStrings)) { foreach (string KeySource in SecondaryEncryptionKeyStrings) { EncryptionKey NewKey = new EncryptionKey(); SecondaryEncryptionKeys.Add(NewKey); Regex Search = new Regex("\\(Guid=(?\'Guid\'.*),Name=\\\"(?\'Name\'.*)\\\",Key=\\\"(?\'Key\'.*)\\\"\\)"); Match Match = Search.Match(KeySource); if (Match.Success) { foreach (string GroupName in Search.GetGroupNames()) { string Value = Match.Groups[GroupName].Value; if (GroupName == "Guid") { NewKey.Guid = Value; } else if (GroupName == "Name") { NewKey.Name = Value; } else if (GroupName == "Key") { NewKey.Key = System.Convert.FromBase64String(Value); } } } } } Settings.SecondaryEncryptionKeys = SecondaryEncryptionKeys.ToArray(); // Parse signing key string PrivateExponent, PublicExponent, Modulus; Ini.GetString(SectionName, "SigningPrivateExponent", out PrivateExponent); Ini.GetString(SectionName, "SigningModulus", out Modulus); Ini.GetString(SectionName, "SigningPublicExponent", out PublicExponent); if (!String.IsNullOrEmpty(PrivateExponent) && !String.IsNullOrEmpty(PublicExponent) && !String.IsNullOrEmpty(Modulus)) { Settings.SigningKey = new SigningKeyPair(); Settings.SigningKey.PublicKey.Exponent = System.Convert.FromBase64String(PublicExponent); Settings.SigningKey.PublicKey.Modulus = System.Convert.FromBase64String(Modulus); Settings.SigningKey.PrivateKey.Exponent = System.Convert.FromBase64String(PrivateExponent); Settings.SigningKey.PrivateKey.Modulus = Settings.SigningKey.PublicKey.Modulus; } } // Parse project dynamic keychain keys if (InProjectDirectory != null) { ConfigHierarchy GameIni = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, InProjectDirectory, InTargetPlatform); if (GameIni != null) { string Filename; if (GameIni.GetString("ContentEncryption", "ProjectKeyChain", out Filename)) { FileReference ProjectKeyChainFile = FileReference.Combine(InProjectDirectory, "Content", Filename); if (FileReference.Exists(ProjectKeyChainFile)) { List <EncryptionKey> EncryptionKeys = new List <EncryptionKey>(); if (Settings.SecondaryEncryptionKeys != null) { EncryptionKeys.AddRange(Settings.SecondaryEncryptionKeys); } string[] Lines = FileReference.ReadAllLines(ProjectKeyChainFile); foreach (string Line in Lines) { string[] KeyParts = Line.Split(':'); if (KeyParts.Length == 4) { EncryptionKey NewKey = new EncryptionKey(); NewKey.Name = KeyParts[0]; NewKey.Guid = KeyParts[2]; NewKey.Key = System.Convert.FromBase64String(KeyParts[3]); EncryptionKey ExistingKey = EncryptionKeys.Find((EncryptionKey OtherKey) => { return(OtherKey.Guid == NewKey.Guid); }); if (ExistingKey != null && !CompareKey(ExistingKey.Key, NewKey.Key)) { throw new Exception("Found multiple encryption keys with the same guid but different AES keys while merging secondary keys from the project key-chain!"); } EncryptionKeys.Add(NewKey); } } Settings.SecondaryEncryptionKeys = EncryptionKeys.ToArray(); } } } } if (!Settings.bDataCryptoRequired) { CryptoSettings NewSettings = new CryptoSettings(); NewSettings.SecondaryEncryptionKeys = Settings.SecondaryEncryptionKeys; Settings = NewSettings; } else { if (!Settings.PakSigningRequired) { Settings.bEnablePakSigning = false; Settings.SigningKey = null; } if (!Settings.PakEncryptionRequired) { Settings.bEnablePakFullAssetEncryption = false; Settings.bEnablePakIndexEncryption = false; Settings.bEnablePakIniEncryption = false; Settings.EncryptionKey = null; Settings.SigningKey = null; } } // Check if we have a valid signing key that is of the old short form if (Settings.SigningKey != null && Settings.SigningKey.IsValid() && Settings.SigningKey.IsUnsecureLegacyKey()) { Log.TraceWarningOnce("Project signing keys found in '{0}' are of the old insecure short format. Please regenerate them using the project crypto settings panel in the editor!", InProjectDirectory); } // Validate the settings we have read if (Settings.bDataCryptoRequired && Settings.bEnablePakSigning && (Settings.SigningKey == null || !Settings.SigningKey.IsValid())) { Log.TraceWarningOnce("Pak signing is enabled, but no valid signing keys were found. Please generate a key in the editor project crypto settings. Signing will be disabled"); Settings.bEnablePakSigning = false; } if (Settings.bDataCryptoRequired && Settings.IsAnyEncryptionEnabled() && (Settings.EncryptionKey == null || !Settings.EncryptionKey.IsValid())) { Log.TraceWarningOnce("Pak encryption is enabled, but no valid encryption key was found. Please generate a key in the editor project crypto settings. Encryption will be disabled"); Settings.bEnablePakUAssetEncryption = false; Settings.bEnablePakFullAssetEncryption = false; Settings.bEnablePakIndexEncryption = false; Settings.bEnablePakIniEncryption = false; } return(Settings); }
/// <summary> /// Parse crypto settings from INI file /// </summary> public static CryptoSettings ParseCryptoSettings(DirectoryReference InProjectDirectory, UnrealTargetPlatform InTargetPlatform) { CryptoSettings Settings = new CryptoSettings(); ConfigHierarchy Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, InProjectDirectory, InTargetPlatform); Ini.GetBool("PlatformCrypto", "PlatformRequiresDataCrypto", out Settings.bDataCryptoRequired); // For now, we'll just not parse any keys if data crypto is disabled for this platform. In the future, we might want to use // these keys for non-data purposes (other general purpose encryption maybe?) if (!Settings.bDataCryptoRequired) { return(Settings); } { // Start by parsing the legacy encryption.ini settings Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Encryption, InProjectDirectory, InTargetPlatform); Ini.GetBool("Core.Encryption", "SignPak", out Settings.bEnablePakSigning); string[] SigningKeyStrings = new string[3]; Ini.GetString("Core.Encryption", "rsa.privateexp", out SigningKeyStrings[0]); Ini.GetString("Core.Encryption", "rsa.modulus", out SigningKeyStrings[1]); Ini.GetString("Core.Encryption", "rsa.publicexp", out SigningKeyStrings[2]); if (String.IsNullOrEmpty(SigningKeyStrings[0]) || String.IsNullOrEmpty(SigningKeyStrings[1]) || String.IsNullOrEmpty(SigningKeyStrings[2])) { SigningKeyStrings = null; } else { Settings.SigningKey = new SigningKeyPair(); Settings.SigningKey.PrivateKey.Exponent = ParseHexStringToByteArray(ProcessSigningKeyInputStrings(SigningKeyStrings[0]), 64); Settings.SigningKey.PrivateKey.Modulus = ParseHexStringToByteArray(ProcessSigningKeyInputStrings(SigningKeyStrings[1]), 64); Settings.SigningKey.PublicKey.Exponent = ParseHexStringToByteArray(ProcessSigningKeyInputStrings(SigningKeyStrings[2]), 64); Settings.SigningKey.PublicKey.Modulus = Settings.SigningKey.PrivateKey.Modulus; if ((Settings.SigningKey.PrivateKey.Exponent.Length > 64) || (Settings.SigningKey.PrivateKey.Modulus.Length > 64) || (Settings.SigningKey.PublicKey.Exponent.Length > 64) || (Settings.SigningKey.PublicKey.Modulus.Length > 64)) { throw new Exception(string.Format("[{0}] Signing keys parsed from encryption.ini are too long. They must be a maximum of 64 bytes long!", InProjectDirectory)); } } Ini.GetBool("Core.Encryption", "EncryptPak", out Settings.bEnablePakIndexEncryption); Settings.bEnablePakFullAssetEncryption = false; Settings.bEnablePakUAssetEncryption = false; Settings.bEnablePakIniEncryption = Settings.bEnablePakIndexEncryption; string EncryptionKeyString; Ini.GetString("Core.Encryption", "aes.key", out EncryptionKeyString); Settings.EncryptionKey = new EncryptionKey(); if (EncryptionKeyString.Length > 0) { if (EncryptionKeyString.Length < 32) { Log.WriteLine(LogEventType.Warning, "AES key parsed from encryption.ini is too short. It must be 32 bytes, so will be padded with 0s, giving sub-optimal security!"); } else if (EncryptionKeyString.Length > 32) { Log.WriteLine(LogEventType.Warning, "AES key parsed from encryption.ini is too long. It must be 32 bytes, so will be truncated!"); } Settings.EncryptionKey.Key = ParseAnsiStringToByteArray(EncryptionKeyString, 32); } } Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Crypto, InProjectDirectory, InTargetPlatform); string SectionName = "/Script/CryptoKeys.CryptoKeysSettings"; ConfigHierarchySection CryptoSection = Ini.FindSection(SectionName); // If we have new format crypto keys, read them in over the top of the legacy settings if (CryptoSection != null && CryptoSection.KeyNames.Count() > 0) { Ini.GetBool(SectionName, "bEnablePakSigning", out Settings.bEnablePakSigning); Ini.GetBool(SectionName, "bEncryptPakIniFiles", out Settings.bEnablePakIniEncryption); Ini.GetBool(SectionName, "bEncryptPakIndex", out Settings.bEnablePakIndexEncryption); Ini.GetBool(SectionName, "bEncryptUAssetFiles", out Settings.bEnablePakUAssetEncryption); Ini.GetBool(SectionName, "bEncryptAllAssetFiles", out Settings.bEnablePakFullAssetEncryption); // Parse encryption key string EncryptionKeyString; Ini.GetString(SectionName, "EncryptionKey", out EncryptionKeyString); if (!string.IsNullOrEmpty(EncryptionKeyString)) { Settings.EncryptionKey = new EncryptionKey(); Settings.EncryptionKey.Key = System.Convert.FromBase64String(EncryptionKeyString); } // Parse signing key string PrivateExponent, PublicExponent, Modulus; Ini.GetString(SectionName, "SigningPrivateExponent", out PrivateExponent); Ini.GetString(SectionName, "SigningModulus", out Modulus); Ini.GetString(SectionName, "SigningPublicExponent", out PublicExponent); if (!String.IsNullOrEmpty(PrivateExponent) && !String.IsNullOrEmpty(PublicExponent) && !String.IsNullOrEmpty(Modulus)) { Settings.SigningKey = new SigningKeyPair(); Settings.SigningKey.PublicKey.Exponent = System.Convert.FromBase64String(PublicExponent); Settings.SigningKey.PublicKey.Modulus = System.Convert.FromBase64String(Modulus); Settings.SigningKey.PrivateKey.Exponent = System.Convert.FromBase64String(PrivateExponent); Settings.SigningKey.PrivateKey.Modulus = Settings.SigningKey.PublicKey.Modulus; } } return(Settings); }