Сделать запутывание строки компилятора


Я смотрю на задачу, чтобы скрыть strings в моем приложении как URL, пути и запросов во время компиляции. Это не для шифрования connectionStrings, passwords или другие конфиденциальные данные, что делается с protected section в App.Config и уже обращаться в другие вопросы.

https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/connection-strings-and-configuration-files#appconfig-example

https://stackoverflow.com/a/4155307/3850405

Я также полностью осознаю, что все, что я делаю может быть сломан, и да security through obscurity был отвергнут еще в 1851 и в последние годы даже для .Чистая. Это не суть вопроса.

https://stackoverflow.com/a/506301/3850405

С этими высказываниями в сторону, давайте посмотрим на проблему под рукой:

  • Принять запутывание строки компилятора. Я видел некоторые примеры на C++ с использованием препроцессора при компиляции, но это не то, чего я хочу. С учетом директивы препроцессора c# я не думаю, что это может быть сделано, как это. https://stackoverflow.com/a/4102533/3850405и https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives/
  • Сгенерированные символы не должны сталкиваться
  • Идентичные строки не должны выглядеть одинаково

Я решил написать Stand-Alone Code Analysis Tool для .Net компилятор платформы Roslyn.

https://github.com/dotnet/roslyn/wiki/Getting-Started-C%23-Syntax-Analysis

Программа шифрует строку, используя следующий алгоритм:

https://stackoverflow.com/a/10177020/3850405

Затем программа создает случайный пароль для каждой строки делать те же значения, уникальные и затем добавляет расшифровать метод решения. Требует using System.Security.Cryptography; для расшифровки метода.

Код имеет некоторые ограничения с Attributes и обработки " уцелевший в строках и т. д. Однако хотелось бы больше знать, если я на правильном пути или пропустил что-то очевидное.

Программа, созданная для задач:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Text;
    using Microsoft.CodeAnalysis;
    using Microsoft.CodeAnalysis.CSharp;
    using Microsoft.CodeAnalysis.CSharp.Symbols;
    using Microsoft.CodeAnalysis.CSharp.Syntax;
    using Microsoft.CodeAnalysis.Editing;
    using Microsoft.CodeAnalysis.Formatting;
    using Microsoft.CodeAnalysis.MSBuild;
    using Microsoft.CodeAnalysis.Simplification;
    using Microsoft.CodeAnalysis.Text;

    namespace StringObfuscation
    {
        class Program
        {
            static void Main(string[] args)
            {
                var workspace = new AdhocWorkspace();
                var projectId = ProjectId.CreateNewId();
                var versionStamp = VersionStamp.Create();
                var projectInfo = ProjectInfo.Create(projectId, versionStamp, "NewProject", "projName", LanguageNames.CSharp);
                var newProject = workspace.AddProject(projectInfo);

                var sourceText = SourceText.From(
                    @"
                      using System;
                      using System.IO;
                      using System.Linq;
                      using System.Security.Cryptography;
                      using System.Text;

                      namespace HelloWorld
                      {
                          class Program
                          {
                              static void Main(string[] args)
                              {
                                  var varTest1 = ""test var"";

                                  var varTest2 = ""test var"";

                                  string test1 = ""test string"";

                                  String test2 = ""test String"";

                                  const string test3 = ""test const""; 

                                  readonly string test4 = ""test readonly""; 

                                  int i = 0;

                                  var i2 = 0;

                                  var test5 = Test(""Testing"");

                                  var test6 = Test(""Testing"", ""Testing 2"", 1);

                                  string test7 = ""test symbols \r\n © @ {} [] <> | / \ $£@!\#¤%&/()=?`""; 
                              }

                              public static string Test(string test)
                              {
                                  return test;
                              }

                              public static string Test(string test, string test2, int test3)
                              {
                                  return test + test2 + test3;
                              }
                          }
                      }");

                var document = workspace.AddDocument(newProject.Id, "NewFile.cs", sourceText);
                var syntaxRoot = document.GetSyntaxRootAsync().Result;

                var root = (CompilationUnitSyntax)syntaxRoot;

                var mainNode = root.DescendantNodes()
                    .OfType<MethodDeclarationSyntax>().FirstOrDefault(x => x.Identifier.ValueText == "Main"
                                                                           && x.ParameterList.Parameters.FirstOrDefault().Identifier.ValueText == "args");

                var editor = DocumentEditor.CreateAsync(document).Result;

                SeparatedSyntaxList<ParameterSyntax> parametersList = new SeparatedSyntaxList<ParameterSyntax>().AddRange
                (new ParameterSyntax[]
                    {
                        SyntaxFactory.Parameter(SyntaxFactory.Identifier("one")).WithType(SyntaxFactory.ParseTypeName("string")),
                        SyntaxFactory.Parameter(SyntaxFactory.Identifier("two")).WithType(SyntaxFactory.ParseTypeName("string")),
                    }
                );

                var syntax = SyntaxFactory.ParseStatement(@"
                const int k = 256;

                const int dI = 1000;

                var cTBWSAI = Convert.FromBase64String(one);
                var ssB = cTBWSAI.Take(k / 8).ToArray();
                var iSB = cTBWSAI.Skip(k / 8).Take(k / 8).ToArray();
                var cTB = cTBWSAI.Skip((k / 8) * 2).Take(cTBWSAI.Length - ((k / 8) * 2)).ToArray();

                using (var p = new Rfc2898DeriveBytes(two, ssB, dI))
                {
                    var kB = p.GetBytes(k / 8);
                    using (var sK = new RijndaelManaged())
                    {
                        sK.BlockSize = 256;
                        sK.Mode = CipherMode.CBC;
                        sK.Padding = PaddingMode.PKCS7;
                        using (var d = sK.CreateDecryptor(kB, iSB))
                        {
                            using (var mS = new MemoryStream(cTB))
                            {
                                using (var cS = new CryptoStream(mS, d, CryptoStreamMode.Read))
                                {
                                    var pTB = new byte[cTB.Length];
                                    var dBC = cS.Read(pTB, 0, pTB.Length);
                                    mS.Close();
                                    cS.Close();
                                    return Encoding.UTF8.GetString(pTB, 0, dBC);
                                }
                            }
                        }
                    }
                }
            ");

                //Add StringManipulation method 
                var newMethod = SyntaxFactory.MethodDeclaration(
                    SyntaxFactory.List<AttributeListSyntax>(),
                    SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)),
                    SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.StringKeyword)),
                    null,
                    SyntaxFactory.Identifier("D"),
                    null,
                    SyntaxFactory.ParameterList(parametersList),
                    SyntaxFactory.List<TypeParameterConstraintClauseSyntax>(),
                    SyntaxFactory.Block(syntax),
                    null
                );

                newMethod = newMethod.NormalizeWhitespace();

                //Insert after mainNode
                editor.InsertAfter(mainNode, newMethod);

                var invocationExpressions = root.DescendantNodes()
                    .OfType<InvocationExpressionSyntax>();

                foreach (var invocationExpressionSyntax in invocationExpressions)
                {
                    //Replace method calls with hard coded strings
                    if (invocationExpressionSyntax.ArgumentList.Arguments.Any(x =>
                        x.Expression.Kind() == SyntaxKind.StringLiteralExpression))
                    {

                        var stringList = new List<string>();

                        for (int i = 0; i < invocationExpressionSyntax.ArgumentList.Arguments.Count(); i++)
                        {
                            if (invocationExpressionSyntax.ArgumentList.Arguments[i].Expression.Kind() == SyntaxKind.StringLiteralExpression)
                            {
                                var value = invocationExpressionSyntax.ArgumentList.Arguments[i].Expression.GetFirstToken().ValueText;

                                var password = RandomString(40);

                                var encryptedText = StringCipher.Encrypt(value, password);
                                stringList.Add($"D(\"{encryptedText}\", \"{password}\")");
                            }
                            else
                            {
                                stringList.Add(invocationExpressionSyntax.ArgumentList.Arguments[i].Expression
                                    .GetFirstToken().ValueText);
                            }
                        }

                        SeparatedSyntaxList<ArgumentSyntax> arguments = new SeparatedSyntaxList<ArgumentSyntax>().AddRange
                        (new ArgumentSyntax[]
                            {
                                SyntaxFactory.Argument(SyntaxFactory.ParseExpression($"{string.Join(",", stringList)}")),
                            }
                        );

                        var newMethodWithStringObfuscation =
                            SyntaxFactory
                                .InvocationExpression(SyntaxFactory.IdentifierName(invocationExpressionSyntax.Expression
                                    .GetFirstToken().ValueText))
                                .WithArgumentList(
                                    SyntaxFactory.ArgumentList()
                                        .WithOpenParenToken(
                                            SyntaxFactory.Token(
                                                SyntaxKind.OpenParenToken))
                                        .WithArguments(arguments)
                                        .WithCloseParenToken(
                                            SyntaxFactory.Token(
                                                SyntaxKind.CloseParenToken)));

                        newMethodWithStringObfuscation = newMethodWithStringObfuscation.NormalizeWhitespace();

                        Console.WriteLine($"Replacing values for method {invocationExpressionSyntax.Expression.GetFirstToken().ValueText}");

                        editor.ReplaceNode(invocationExpressionSyntax, newMethodWithStringObfuscation);
                    }
                }

                var localDeclaration = new LocalDeclarationVirtualizationVisitor();
                localDeclaration.Visit(root);

                var localDeclarations = localDeclaration.LocalDeclarations;

                foreach (var localDeclarationStatementSyntax in localDeclarations)
                {
                    foreach (VariableDeclaratorSyntax variable in localDeclarationStatementSyntax.Declaration.Variables)
                    {

                        var stringKind = variable.Initializer.Value.Kind();

                        //Replace string variables
                        if (stringKind == SyntaxKind.StringLiteralExpression)
                        {
                            var value = variable.Initializer.Value.ToString();
                            //Remove " from start and end of string
                            value = value.Remove(0, 1);
                            value = value.Remove(value.Length - 1, 1);
                            var password = RandomString(40);

                            var encryptedText = StringCipher.Encrypt(value, password);

                            var newVariable = SyntaxFactory.ParseStatement($"string {variable.Identifier.ValueText} = D(\"{encryptedText}\", \"{password}\"); {System.Environment.NewLine}");
                            //var newVariable = SyntaxFactory.ParseStatement($"string {variable.Identifier.ValueText} = D(\"{value}\"); {System.Environment.NewLine}").WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation);

                            //newVariable = newVariable.NormalizeWhitespace();

                            editor.ReplaceNode(variable, newVariable);

                            Console.WriteLine($"Key: {variable.Identifier.Value} Value:{variable.Initializer.Value}");
                        }
                    }
                }

                var newDocument = editor.GetChangedDocument();

                var text = newDocument.GetTextAsync().Result.ToString();
            }

            private static Random random = new Random();
            public static string RandomString(int length)
            {
                const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
                return new string(Enumerable.Repeat(chars, length)
                    .Select(s => s[random.Next(s.Length)]).ToArray());
            }
        }

        class LocalDeclarationVirtualizationVisitor : CSharpSyntaxRewriter
        {
            public LocalDeclarationVirtualizationVisitor()
            {
                LocalDeclarations = new List<LocalDeclarationStatementSyntax>();
            }

            public List<LocalDeclarationStatementSyntax> LocalDeclarations { get; set; }

            public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
            {
                node = (LocalDeclarationStatementSyntax)base.VisitLocalDeclarationStatement(node);
                LocalDeclarations.Add(node);
                return node;
            }
        }



        public static class StringCipher
        {
            // This constant is used to determine the keysize of the encryption algorithm in bits.
            // We divide this by 8 within the code below to get the equivalent number of bytes.
            private const int Keysize = 256;

            // This constant determines the number of iterations for the password bytes generation function.
            private const int DerivationIterations = 1000;

            public static string Encrypt(string plainText, string passPhrase)
            {
                // Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
                // so that the same Salt and IV values can be used when decrypting.  
                var saltStringBytes = Generate256BitsOfRandomEntropy();
                var ivStringBytes = Generate256BitsOfRandomEntropy();
                var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
                using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
                {
                    var keyBytes = password.GetBytes(Keysize / 8);
                    using (var symmetricKey = new RijndaelManaged())
                    {
                        symmetricKey.BlockSize = 256;
                        symmetricKey.Mode = CipherMode.CBC;
                        symmetricKey.Padding = PaddingMode.PKCS7;
                        using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
                        {
                            using (var memoryStream = new MemoryStream())
                            {
                                using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                                {
                                    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                                    cryptoStream.FlushFinalBlock();
                                    // Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
                                    var cipherTextBytes = saltStringBytes;
                                    cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
                                    cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
                                    memoryStream.Close();
                                    cryptoStream.Close();
                                    return Convert.ToBase64String(cipherTextBytes);
                                }
                            }
                        }
                    }
                }
            }

            public static string Decrypt(string cipherText, string passPhrase)
            {
                // Get the complete stream of bytes that represent:
                // [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
                var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
                // Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
                var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
                // Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
                var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
                // Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
                var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();

                using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
                {
                    var keyBytes = password.GetBytes(Keysize / 8);
                    using (var symmetricKey = new RijndaelManaged())
                    {
                        symmetricKey.BlockSize = 256;
                        symmetricKey.Mode = CipherMode.CBC;
                        symmetricKey.Padding = PaddingMode.PKCS7;
                        using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
                        {
                            using (var memoryStream = new MemoryStream(cipherTextBytes))
                            {
                                using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                                {
                                    var plainTextBytes = new byte[cipherTextBytes.Length];
                                    var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                                    memoryStream.Close();
                                    cryptoStream.Close();
                                    return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
                                }
                            }
                        }
                    }
                }
            }

            private static byte[] Generate256BitsOfRandomEntropy()
            {
                var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
                using (var rngCsp = new RNGCryptoServiceProvider())
                {
                    // Fill the array with cryptographically secure random bytes.
                    rngCsp.GetBytes(randomBytes);
                }
                return randomBytes;
            }

            //Method used for application
            public static string D(string one, string two)
            {
                const int k = 256;

                const int dI = 1000;

                var cTBWSAI = Convert.FromBase64String(one);
                var ssB = cTBWSAI.Take(k / 8).ToArray();
                var iSB = cTBWSAI.Skip(k / 8).Take(k / 8).ToArray();
                var cTB = cTBWSAI.Skip((k / 8) * 2).Take(cTBWSAI.Length - ((k / 8) * 2)).ToArray();

                using (var p = new Rfc2898DeriveBytes(two, ssB, dI))
                {
                    var kB = p.GetBytes(k / 8);
                    using (var sK = new RijndaelManaged())
                    {
                        sK.BlockSize = 256;
                        sK.Mode = CipherMode.CBC;
                        sK.Padding = PaddingMode.PKCS7;
                        using (var d = sK.CreateDecryptor(kB, iSB))
                        {
                            using (var mS = new MemoryStream(cTB))
                            {
                                using (var cS = new CryptoStream(mS, d, CryptoStreamMode.Read))
                                {
                                    var pTB = new byte[cTB.Length];
                                    var dBC = cS.Read(pTB, 0, pTB.Length);
                                    mS.Close();
                                    cS.Close();
                                    return Encoding.UTF8.GetString(pTB, 0, dBC);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

Генерирует вывод такой:

using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            string varTest1 = D("Z7Jk/l0olcmT2KBXth65F1IGGgod2t1TSU09sfUQAveyYgP2DRK+pU8DWwTgnVNbEZtm+GrrokQzW4pu6csH8RFQ93/YVXUObzE7//fWt2D3USlL/+PLkgyl51L1OH+b", "rMLEdXF0APXum1hBaPgNNasgNyiw2pe68rNFsYDt");
            string varTest2 = D("5Z/R9caz7fZlqFSBBuU6qlUVyG8FSIC64ryrhCgGXdSpbHrcKNp/0wQlos1u4PmBK/twHDhFwXlmrRa+RnHQcpJAmJVgz92PcpenDNhVqzRSQzHgGGi7lLnLrxypH7ru", "82FNFTiFQsStJ2KQdo0pzS8Vuaw5ncSCLxPUVfa4");

            string test1 = D("Hc6zdWqh4D3fIMJ7YmtMGVispS104s9HuSug7Yec3EoVdzpwxSSwiwZ9fifr7SYITmmsk/yZpId3n6wRdrNB1DPJZ5vQrMnXvtET01JzrNpGNXi9XpshmZ5lrSdRpV97", "QcgJWvxFg7lEhX4q4ucohmbxaQhVn047N6ZWvy99");
            string test2 = D("q8i/0yaXWTQW0iiVOauTom83aT4SLwBJ+O624k+VyKDFcioZ3dg86H1wGq3Wor4hp6Uw7bmfDp44FJ4K2wQ3pUSwJKXT+j3C8aPcOOSNicRyv/4bXSfGZ1G8KBXVyycA", "nqYq1Oey3iZlDvWnBttFObcqCo0l8h4GudB0Ou6L");
            string test3 = D("iColKdv//95gV3TrR5t4Wp3Idw/atPOdbjsRefYifOSLjArhkwwym6ZI5+/SjHP5PuDUyUZqL0WAm8ypmn519mHeS0BD0dzr/MwxVbwsqgUhNmFcVPkfnU2ONqR49vhh", "vtcEaT3bjwVCF3vLOroNY3zVoT0kugYQwhTe8XQs");
            string test4 = D("e7P8NjT3N3L+J+LqksYE0Sb3EeC0Pjyci9dR+/MWlli91RkOppEe3IWXo5Ku6S1AiEwl0VySdRfmdawRZR4ycjklLcDDnuMJDA3uRh9keO9PKxljtaU+tdlw9JGbr7ng", "uYBMM2A1s0lgGtx23HaGdTrDXEPhjQM1b5c91nJw");

            int i = 0;

            var i2 = 0;

            var test5 = Test(D("76xRXN7Ce9PY+2GzzbjOw2leRikd/mTQ6AuRcO2310gXNwePAQnlmyFwQzwTh9bvi2s2+KSz/7rrKEScLfgL0RvdHOOqCk3UyKggbLH05lTE5MeWt/QRPkqEo63X+iYR", "KAnIpTi9XcPvpiUH4tZ77QH4e9rwpAIBXeL1OORA"));

            var test6 = Test(D("05EHgVaf0rYqY8V1qKqzsTdh7jrYQDox8BhggVXBJNL/EyyXw34kQ3B0ooewBap1Xf9hvy96LnZmFN4TgjxqDmpm3JhvapEnyGLmojoY+xRt210MTCjyZcWn+p+T7C01", "O6bZIpEyAAtLeLe32snpmvTXUNYLWd3qcYtAzrvz"), D("/v7Dhz10OV9p2guTI4sKkTdRQty2VxA7txaJ5Sv3OljmqU7LpYqu8InNxizDtJQw1JhMW8Zntw3cX+TPwxkEqwlMMKz6Pl0KTfBCw/4GVqSaP7q5K66tQdZiKprBGwuK", "42woR6gLAS9fkmYdmEF4R3chHDtFcdEK7yut8pGY"), 1);

            string test7 = D("0wk1lng5GYEOneTieY0I4LDlwWgNVBEgmsaqkg4n6Qzaoc+3TKxxYsNZWYjtroaAIF9md/2Oz7RXO2w5DaJq3jUHpRwPpUu8P7r75eEsoBU79J0HXBN7z4ZbiVA69jYHSOXY/dw++7yZKc+1MCG5yiDDpjyDpNpZZsxub0OiJ8o=", "S82442JDubl17JPaq8yHmcRbnuELQxBP7nxebxIf");
        }
        public static string D(string one, string two)
        {
            const int k = 256; const int dI = 1000; var cTBWSAI = Convert.FromBase64String(one); var ssB = cTBWSAI.Take(k / 8).ToArray(); var iSB = cTBWSAI.Skip(k / 8).Take(k / 8).ToArray(); var cTB = cTBWSAI.Skip((k / 8) * 2).Take(cTBWSAI.Length - ((k / 8) * 2)).ToArray(); using (var p = new Rfc2898DeriveBytes(two, ssB, dI)) { var kB = p.GetBytes(k / 8); using (var sK = new RijndaelManaged()) { sK.BlockSize = 256; sK.Mode = CipherMode.CBC; sK.Padding = PaddingMode.PKCS7; using (var d = sK.CreateDecryptor(kB, iSB)) { using (var mS = new MemoryStream(cTB)) { using (var cS = new CryptoStream(mS, d, CryptoStreamMode.Read)) { var pTB = new byte[cTB.Length]; var dBC = cS.Read(pTB, 0, pTB.Length); mS.Close(); cS.Close(); return Encoding.UTF8.GetString(pTB, 0, dBC); } } } } }
        }
        public static string Test(string test)
        {
            return test;
        }

        public static string Test(string test, string test2, int test3)
        {
            return test + test2 + test3;
        }
    }
}


1413
5
задан 22 марта 2018 в 10:03 Источник Поделиться
Комментарии
2 ответа

Я не буду рассматривать сам код, а алгоритм вы используете. Учитывая, что:


  • Пароль доступен (он добавляется к зашифрованной строки).

  • Алгоритм вполне понятен и доступен (тем более, что они видят вызов функции, когда строка является фактически используется).

  • Вы можете использовать самый сложный алгоритм вы хотите, но вы разворачиваете свой алгоритм вместе с ваш код, кто угодно, но стороннему наблюдателю потребуется менее пяти минут, чтобы расшифровать все строки.

В связи с вышесказанным, я думаю, что это решение является сложным и медленным (не забудьте, что струны часто используются) без какой-либо дополнительной выгоды за простой запутывания. Случайный наблюдатель имеет те же шансы, чтобы читать эти строки, а кто-то активно пытается их читать, будет делать это менее чем за пять минут.

Ваша цель, чтобы скрыть эту строку? Шифрование не добавляет ничего более простого кодирования, затем сохранить его простым. Даже простая кодировка base-64 (который вы уже используете) может делать свою работу.

string Encode(string text)
=> Convert.ToBase64String(text);

Восстановить исходную строку, достаточно прост. Это, однако, не рассматривает ваши требования имеют различные значения при шифровании одной и той же строки. Я не знаю, если это действительно полезно, но решение такое же простое, как и предыдущий, только добавить случайное число (или прогрессивный показатель, как хотите):

string Encode(string text)
{
// This is the byte array that will be base-64 encoded.
var bytes = new byte[Encoding.UTF8.GetByteCount(text) + 1];

// First element of the array is also the random value added to each
// character to highly reduce chances of collisions. UTF8 encoded
// string starts after that.
bytes[0] = _rnd.next(1, 255);
Encoding.UTF8.GetBytes(text, 0, text.Length, bytes, 1);

unchecked
{
for (int i=1; i < bytes.Length; ++i)
bytes[i] += bytes[0];
}

return Convert.ToBase64String(bytes);
}

Преимущества? Это быстрее и проще по-прежнему предлагает тот же уровень защиты против случайного наблюдателя. Мы можем сделать лучше? Я честно думаю, что вам даже не нужно кодировать значение запутывание в виде строки:

byte[] Encode(string text) { ... }

Затем сгенерированный код будет:

string test = D({1, 2, 3, ...});

Мы можем сделать лучше? Только если вам это действительно нужно, вы можете рассмотреть, чтобы сгруппировать все строки в словарь и хранить его в сжатом ресурсе. Затем сгенерированный код будет:

string test = D(123);

Это имеет то преимущество, что строки теперь только идентификаторы (как мы делаем в ресурсе файлов Win32). Если дублировать код по-прежнему проблема, тогда вы можете использовать список, а не словарь (а сжатие будет делать все остальное).


Несколько заметок о код (но не исчерпывающий):


  • В C# 7.1 позволяет async Main()это путь (вместо вызова Task.Result()).

  • Если вы используете c# 7 (или ниже) вы, вероятно, следует избегать Task.Result() в пользу Task.GetAwaiter().GetResult(). Они делают ту же работу (сделать звонок синхронно) но есть и не столь тонкие различия об обработке исключений. В большинстве случаев незавернутые исключение трассировки стека рассчитывается с учетом асинхронной связи является то, что вы хотите.

  • Ваш Main() метод-это целая программа. Чтобы отдаленно понять, что он делает, я должен все это читать. В шесть месяцев вам потребуется такое же усилие, чтобы понять свой собственный код. Разделить его на (много!) небольшим объяснением функций и классов. Это проще для понимания, отладки и тестирования (не думаю, что ваш тест является исчерпывающим).

  • Вы должны обрабатывать ошибки. Например, потому что ваш инструмент не правильно обрабатывать выражения, вы не хотите, чтобы разбить все, но просто игнорируют (с предупреждением), что вы не можете справиться.

3
ответ дан 22 марта 2018 в 01:03 Источник Поделиться

На основе ответа от @AdrianoRepetti я создал следующий класс. Я тоже реализовал Task.GetAwaiter().GetResult() и перенес код в другие классы.

public static class StringCipher
{
private static readonly Random random = new Random();
private static readonly object syncLock = new object();

public static byte[] Encode(string text)
{
// This is the byte array that will be base-64 encoded.
var bytes = new byte[Encoding.UTF8.GetByteCount(text) + 1];

// First element of the array is also the random value added to each
// character to highly reduce chances of collisions. UTF8 encoded
// string starts after that.
lock (syncLock)
{
random.NextBytes(bytes);
}

Encoding.UTF8.GetBytes(text, 0, text.Length, bytes, 1);

unchecked
{
for (int i = 1; i < bytes.Length; ++i)
bytes[i] += bytes[0];
}

var base64String = Convert.ToBase64String(bytes);

byte[] newBytes = Encoding.ASCII.GetBytes(base64String);

return newBytes;
}

public static string Decode(byte[] bytes)
{

string someString = Encoding.ASCII.GetString(bytes);

byte[] data = Convert.FromBase64String(someString);

unchecked
{
for (int i = 1; i < data.Length; ++i)
data[i] -= data[0];
}

data = data.Skip(1).ToArray();

string decodedString = Encoding.UTF8.GetString(data);

return decodedString;
}
}

Затем я могу использовать его как это:

var encodedBytes = StringCipher.Encode(stringValue);
stringList.Add($"D({PrintByteArray(encodedBytes)})");

private string PrintByteArray(byte[] bytes)
{
var sb = new StringBuilder("new byte[] { ");
for (var i = 0; i < bytes.Length; i++)
{
var b = bytes[i];
sb.Append(b);
if (i < bytes.Length - 1)
{
sb.Append(", ");
}
}
sb.Append(" }");
return sb.ToString();
}

0
ответ дан 28 марта 2018 в 10:03 Источник Поделиться