From 23574ac645c90610862cc2b3ddecb8e3dc57f702 Mon Sep 17 00:00:00 2001 From: Gan Keyu Date: Sat, 12 Aug 2023 13:50:14 +0800 Subject: [PATCH 1/2] remove reflections from poifs.encryption --- main/POIFS/Crypt/EncryptionInfo.cs | 49 +++++++++++++++++++++++------- main/POIFS/Crypt/EncryptionMode.cs | 13 +++++--- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/main/POIFS/Crypt/EncryptionInfo.cs b/main/POIFS/Crypt/EncryptionInfo.cs index 3b243594d..facb15fae 100644 --- a/main/POIFS/Crypt/EncryptionInfo.cs +++ b/main/POIFS/Crypt/EncryptionInfo.cs @@ -22,7 +22,8 @@ limitations under the License. namespace NPOI.POIFS.Crypt { using System; - using System.Reflection; + using System.Diagnostics.CodeAnalysis; + using System.Net.Security; public class EncryptionInfo { @@ -292,23 +293,49 @@ EncryptionMode encryptionMode _encryptor = eib.GetEncryptor(); } + // REMOVE-REFLECTION: Remove reflections here will prevent NPOI from creating custom encryptors. + // Is it OK? Remove reflection-related code for now. + // It might be better to move Agile classes definition into this library. Now it's defined in NPOI.OOXML.Core. protected static IEncryptionInfoBuilder GetBuilder(EncryptionMode encryptionMode) { - Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); - Type t = null; - foreach (Assembly assembly in assemblies) + switch (encryptionMode.Builder) { - t = assembly.GetType(encryptionMode.Builder); - if (t != null) + case EncryptionMode.BuilderNameBinaryRC4: + return new BinaryRC4.BinaryRC4EncryptionInfoBuilder(); + case EncryptionMode.BuilderNameCryptoAPI: + return new CryptoAPI.CryptoAPIEncryptionInfoBuilder(); + case EncryptionMode.BuilderNameStandard: + return new Standard.StandardEncryptionInfoBuilder(); + case EncryptionMode.BuilderNameAgile: + // return new Agile.AgileEncryptionInfoBuilder(); + // TODO + IEncryptionInfoBuilder instance = CreateAgileInstanceFallback(); + if (instance is not null) + return instance; break; } - if (t == null) + + throw new EncryptedDocumentException("Not found type " + encryptionMode.Builder); + } + + private static Type AgileEncrpytionInfo; + +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("Agile must be dynamically loaded from NPOI.OOXML. TODO.")] +#endif + private static IEncryptionInfoBuilder CreateAgileInstanceFallback() + { + if (AgileEncrpytionInfo is null) { - throw new EncryptedDocumentException("Not found type " + encryptionMode.Builder); + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + if ((AgileEncrpytionInfo = assembly.GetType(EncryptionMode.BuilderNameAgile)) != null) + break; } - IEncryptionInfoBuilder eib = null; - eib = (IEncryptionInfoBuilder)t.Assembly.CreateInstance(encryptionMode.Builder); - return eib; + + if (AgileEncrpytionInfo is null) + return null; + + return (IEncryptionInfoBuilder)Activator.CreateInstance(AgileEncrpytionInfo); } private int _versionMajor; diff --git a/main/POIFS/Crypt/EncryptionMode.cs b/main/POIFS/Crypt/EncryptionMode.cs index a5f0e28e4..5976b8ec6 100644 --- a/main/POIFS/Crypt/EncryptionMode.cs +++ b/main/POIFS/Crypt/EncryptionMode.cs @@ -27,14 +27,19 @@ namespace NPOI.POIFS.Crypt */ public class EncryptionMode { + public const string BuilderNameBinaryRC4 = "NPOI.POIFS.Crypt.BinaryRC4.BinaryRC4EncryptionInfoBuilder"; + public const string BuilderNameCryptoAPI = "NPOI.POIFS.Crypt.CryptoAPI.CryptoAPIEncryptionInfoBuilder"; + public const string BuilderNameStandard = "NPOI.POIFS.Crypt.Standard.StandardEncryptionInfoBuilder"; + public const string BuilderNameAgile = "NPOI.POIFS.Crypt.Agile.AgileEncryptionInfoBuilder"; + /* @see 2.3.6 Office Binary Document RC4 Encryption */ - public static readonly EncryptionMode BinaryRC4 = new EncryptionMode("NPOI.POIFS.Crypt.BinaryRC4.BinaryRC4EncryptionInfoBuilder", 1, 1, 0x0); + public static readonly EncryptionMode BinaryRC4 = new EncryptionMode(BuilderNameBinaryRC4, 1, 1, 0x0); /* @see 2.3.5 Office Binary Document RC4 CryptoAPI Encryption */ - public static readonly EncryptionMode CryptoAPI = new EncryptionMode("NPOI.POIFS.Crypt.CryptoAPI.CryptoAPIEncryptionInfoBuilder", 4, 2, 0x04); + public static readonly EncryptionMode CryptoAPI = new EncryptionMode(BuilderNameCryptoAPI, 4, 2, 0x04); /* @see 2.3.4.5 \EncryptionInfo Stream (Standard Encryption) */ - public static readonly EncryptionMode Standard = new EncryptionMode("NPOI.POIFS.Crypt.Standard.StandardEncryptionInfoBuilder", 4, 2, 0x24); + public static readonly EncryptionMode Standard = new EncryptionMode(BuilderNameStandard, 4, 2, 0x24); /* @see 2.3.4.10 \EncryptionInfo Stream (Agile Encryption) */ - public static readonly EncryptionMode Agile = new EncryptionMode("NPOI.POIFS.Crypt.Agile.AgileEncryptionInfoBuilder", 4, 4, 0x40); + public static readonly EncryptionMode Agile = new EncryptionMode(BuilderNameAgile, 4, 4, 0x40); public string Builder { get; private set; } From 36365be5667555c63fa1ecb3ffe69599709332e8 Mon Sep 17 00:00:00 2001 From: Gan Keyu Date: Sun, 13 Aug 2023 11:39:11 +0800 Subject: [PATCH 2/2] provides an AOT-compatible way to load Agile from OOXML --- main/POIFS/Crypt/EncryptionInfo.cs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/main/POIFS/Crypt/EncryptionInfo.cs b/main/POIFS/Crypt/EncryptionInfo.cs index facb15fae..f3007db1f 100644 --- a/main/POIFS/Crypt/EncryptionInfo.cs +++ b/main/POIFS/Crypt/EncryptionInfo.cs @@ -296,6 +296,10 @@ EncryptionMode encryptionMode // REMOVE-REFLECTION: Remove reflections here will prevent NPOI from creating custom encryptors. // Is it OK? Remove reflection-related code for now. // It might be better to move Agile classes definition into this library. Now it's defined in NPOI.OOXML.Core. +#if NET6_0_OR_GREATER + [DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.Interfaces + | DynamicallyAccessedMemberTypes.PublicMethods, EncryptionMode.BuilderNameAgile, "NPOI.OOXML")] +#endif protected static IEncryptionInfoBuilder GetBuilder(EncryptionMode encryptionMode) { switch (encryptionMode.Builder) @@ -307,8 +311,6 @@ protected static IEncryptionInfoBuilder GetBuilder(EncryptionMode encryptionMode case EncryptionMode.BuilderNameStandard: return new Standard.StandardEncryptionInfoBuilder(); case EncryptionMode.BuilderNameAgile: - // return new Agile.AgileEncryptionInfoBuilder(); - // TODO IEncryptionInfoBuilder instance = CreateAgileInstanceFallback(); if (instance is not null) return instance; @@ -318,24 +320,20 @@ protected static IEncryptionInfoBuilder GetBuilder(EncryptionMode encryptionMode throw new EncryptedDocumentException("Not found type " + encryptionMode.Builder); } - private static Type AgileEncrpytionInfo; - -#if NET6_0_OR_GREATER - [RequiresUnreferencedCode("Agile must be dynamically loaded from NPOI.OOXML. TODO.")] -#endif + private static Type AgileEncryptionInfo; private static IEncryptionInfoBuilder CreateAgileInstanceFallback() { - if (AgileEncrpytionInfo is null) + if (AgileEncryptionInfo is null) { foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - if ((AgileEncrpytionInfo = assembly.GetType(EncryptionMode.BuilderNameAgile)) != null) + if ((AgileEncryptionInfo = assembly.GetType(EncryptionMode.BuilderNameAgile)) != null) break; } - if (AgileEncrpytionInfo is null) + if (AgileEncryptionInfo is null) return null; - return (IEncryptionInfoBuilder)Activator.CreateInstance(AgileEncrpytionInfo); + return (IEncryptionInfoBuilder)Activator.CreateInstance(AgileEncryptionInfo); } private int _versionMajor;