Как отменить процесс этого метода декодирования С# для создания метода кодирования?

Я хотел бы знать, как отменить процесс DecodeBinaryBase64 ниже, чтобы у меня был соответствующий метод Encode. В коротком коде C#, если получить вывод этого метода, он вернет ту же строку, которую он принял в качестве ввода.

private static string DecodeBinaryBase64(string stringToDecode)
{
    StringBuilder builder = new StringBuilder();
    foreach (var b in Convert.FromBase64String(stringToDecode))
        builder.Append(string.Format("{0:X2}", b));
    return builder.ToString();
}

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

ЗАКОДИРОВАНО

/КУГОуоЭСМВЮДб+БТМК1ЛаГе7к=

ДЕКОДИРОВАНО

FCA5063AEA0448C598B836FE05330AD4B6867BB9

or

0xFCA5063AEA0448C598B836FE05330AD4B6867BB9

Обновлено, чтобы отразить правильное значение SHA1 благодаря Porges и исправлению шестнадцатеричной ошибки, обнаруженной Дином 'codeka' Хардином.

Реализованное решение

Вот реализация, которая у меня есть сейчас, она из поста Porges, разделенная на два метода.

private static string EncodeFileDigestBase64(string digest)
{
    byte[] result = new byte[digest.Length / 2];

    for (int i = 0; i < digest.Length; i += 2)
        result[i / 2] = byte.Parse(digest.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);

    if (result.Length != 20)
        throw new ArgumentException("Not a valid SHA1 filedigest.");

    return Convert.ToBase64String(result);
}

private static string DecodeFileDigestBase64(string encodedDigest)
{
    byte[] base64bytes = Convert.FromBase64String(encodedDigest);
    return string.Join(string.Empty, base64bytes.Select(x => x.ToString("X2")));
}  

person Rodney S. Foley    schedule 27.06.2010    source источник


Ответы (3)


Я не верю, что это физически возможно. Проблема в том, что string.Format("{0:X}", b) вернет либо 1, либо 2 символа в зависимости от того, равен ли входной байт ‹ 16 или нет. И у вас нет никакого способа узнать, как только нить была соединена вместе.

Если вы можете изменить метод DecodeBinaryBase64 так, чтобы он всегда добавлял два символа для каждого байта, то есть с помощью string.Format("{0:X2}", b), тогда это будет возможно, просто взяв входную строку по два символа за раз.

Если вы внесли это изменение в свой DecodeBinaryBase64, вы можете использовать следующее для обратного преобразования:

private static string DecodeBinaryBase64(string stringToDecode)
{
    StringBuilder builder = new StringBuilder();
    foreach (var b in Convert.FromBase64String(stringToDecode))
        builder.Append(string.Format("{0:X2}", b));
    return "0x" + builder.ToString();
}

private static string EncodeBinaryBase64(string stringToEncode)
{
    var binary = new List<byte>();
    for(int i = 2; i < stringToEncode.Length; i += 2)
    {
        string s = new string(new [] {stringToEncode[i], stringToEncode[i+1]});
        binary.Add(byte.Parse(s, NumberStyles.HexNumber));
    }
    return Convert.ToBase64String(binary.ToArray());
}

(Однако отсутствует проверка ошибок и т. д.)

person Dean Harding    schedule 27.06.2010
comment
Это, очевидно, возможно, поскольку я получаю закодированную строку от Microsoft в качестве метода, которым они кодируют свои хэши SHA1. Хотя мне не нужно кодировать, я бы очень хотел знать, как это кодировать. Один, чтобы просто знать, и два, которые кажутся полезными, поскольку они могут сделать строку маленькой с помощью base64, что обычно делает их больше. - person Rodney S. Foley; 28.06.2010
comment
@Creepy Gnome: это невозможно по указанной мной причине: string.Format("{0:X}", b) вернет один или два байта в зависимости от того, равно ли b ‹ 16 или нет. Например, возьмите числа: 1, 32, 16 и 4 и соедините их вместе: 132164 — как вы можете снова разложить их обратно на исходные целые числа? - person Dean Harding; 28.06.2010
comment
Вы ограничиваете его реализацией метода Decode. Существует несколько способов декодирования, он показан только как рабочий метод, который идет от A к B, кажется, что перейти от B к A сложнее, но это не невозможно. Как я уже сказал, они каким-то образом кодируют, и именно в этом заключается вопрос о том, как кодировать что-то из B в A, чтобы его можно было декодировать с использованием метода, аналогичного тому, что в вопросе. Я обновлю вопрос примерами строк, которые работают с этим методом. - person Rodney S. Foley; 28.06.2010
comment
@Creepy Gnome: как я уже сказал в своем ответе, если вы измените этот вызов string.Format на string.Format("{0:X2}", b), тогда можно будет снова преобразовать его. Похоже, что строки примеров в вашем вопросе были преобразованы, поскольку там есть 06 и 04: вы бы не увидели этого, если бы вызов string.Format был {0: X}. Я обновлю свой ответ примером. - person Dean Harding; 28.06.2010
comment
Часть, которая не компилируется, это string s = stringToEncode[i] + stringToEncode[i+1]; Чтобы скомпилировать его без изменения алгоритма, мне пришлось сделать эту строку s = new string(new char[] {stringToEncode[i]}) + new string(new char[]{stringToEncode[i+1]}); Поскольку вы не можете преобразовать char в строку, и когда вы добавляете char, вы получаете int, который вы также не можете преобразовать в строку. - person Rodney S. Foley; 28.06.2010
comment
@ Дин, я считаю, что ты усложнил себе задачу, решив не ту проблему. @Creepy Gnome спросил, как кодировать хэш SHA-1 в строку с кодировкой Base-64, а не как перекодировать вывод их метода декодирования! - person porges; 28.06.2010
comment
@Creepy Gnome: это правильно, он меняет вывод, но это потому, что, как я постоянно говорю, алгоритм в исходном вопросе необратим. Информация утеряна и восстановить ее невозможно. Включение /KUGOuoESMWYuDb+BTMK1LaGe7k= в метод DecodeBinaryBase64, который вы написали, дает FCA563AEA448C598B836FE533AD4B6867BB9, что не соответствует вашим словам. - person Dean Harding; 28.06.2010
comment
@Dean, хотя ты прошел долгий путь, и твой код показывает, что мне нужно, и ты добрался до этого первым, я собираюсь дать тебе чек. Однако, если бы не @Proorges, просто заявив, что в моем хэше SHA1 отсутствует байт, который был моей ошибкой из-за плохой копии в прошлом, которая заставила меня использовать X вместо X2. Я согласен с Proges, что вы сделали это сложнее, чем нужно. Я действительно ценю решение и ваши усилия, и я не расстроен, а просто немного разочарован собой и ситуацией. - person Rodney S. Foley; 28.06.2010
comment
@Porges, нет, в ОП четко указано, что они хотят отменить определенный процесс (помеченный как декодирование), а затем определили этот процесс. Ответ: это необратимо, но вот как вы можете сделать это обратимым и, следовательно, ответственным, настолько хорошо, насколько это возможно. - person ; 28.06.2010
comment
@Dean .. PS вы можете отредактировать код для других, которые могут захотеть его использовать, чтобы он скомпилировался для них, поскольку они, скорее всего, не будут читать все комментарии. :) Спасибо еще раз. - person Rodney S. Foley; 28.06.2010
comment
@Dean: алгоритм исходного вопроса необратим - да, но К.Г. не надо переворачивать! :) Им нужно сделать что-то, что предоставит ввод их функции, чтобы их функция могла затем декодировать. - person porges; 28.06.2010
comment
@Isaac: я имею в виду после прочтения комментариев CG здесь. См. первый комментарий: это, очевидно, возможно, поскольку я получаю закодированную строку от Microsoft в качестве метода, которым они кодируют свои хэши SHA1. Хотя мне не нужно кодировать, я бы очень хотел знать, как это кодировать. - person porges; 28.06.2010
comment
@Porges вроде как, а не то, что ошибка, которую я не выпустил, исправлена ​​с помощью X vs X2. У меня есть рабочий метод декодирования. Это то, что мне нужно, чтобы мой проект работал с этими файлами Microsoft XML. Однако из любопытства я хотел знать, как обратить процесс из любой строки в байты в base64. Пример кода Дина будет работать только с SHA1 прямо сейчас с небольшой доработкой, возможно, он сможет работать с любой строкой. - person Rodney S. Foley; 28.06.2010
comment
@Creepy Gnome: Никаких обид :-) Я рад, что мы добрались до конца! Я обновил свой ответ, чтобы код хотя бы компилировался. - person Dean Harding; 28.06.2010
comment
@ Дин, Исаак: смотри мое последнее дополнение к моему ответу. Я предположил, что CG хотела правую инверсию, из-за первого комментария I would really like to know how to encode it и того факта, что вы заметили, что левая инверсия не работает. :) - person porges; 28.06.2010

Ну, вы переходите от Base-64 к строке ASCII/UTF-8, а затем выводите каждый символ как двузначное шестнадцатеричное значение.

Я не знаю никакого способа автоматически вернуть это. Возможно, вам придется вытащить два символа за раз, преобразовать их в «char» и использовать string.format(), чтобы превратить их обратно в символы, возможно?

Я никогда раньше не видел необходимости брать шестнадцатеричный вывод и превращать его обратно в настоящую строку. Надеюсь, это поможет.

person Robert Seder    schedule 27.06.2010

Поэтому я немного расширил свой ответ:

/** Here are the methods in question: **/
string Encode(string input)
{
    return SHA1ToBase64String(StringToBytes(input));
}

string Decode(string input)
{
    return BytesToString(Base64StringToSHA1(input));
}
/****/

string BytesToString(byte[] bytes)
{
    return string.Join("",bytes.Select(x => x.ToString("X2")));
}

byte[] StringToBytes(string input)
{
    var result = new byte[input.Length/2];

    for (var i = 0; i < input.Length; i+=2)
        result[i/2] = byte.Parse(input.Substring(i,2), System.Globalization.NumberStyles.HexNumber);

    return result;
}

string SHA1ToBase64String(byte[] hash)
{
    if (hash.Length != 20)
        throw new Exception("Not an SHA-1 hash.");

    return Convert.ToBase64String(hash);
}

byte[] Base64StringToSHA1(string input)
{
    return Convert.FromBase64String(input);
}

void Main() {

    var encoded = "/KUGOuoESMWYuDb+BTMK1LaGe7k=";

    var decoded = Decode(encoded);
    var reencoded = Encode(decoded);

    Console.WriteLine(encoded == reencoded); //True
    Console.WriteLine(decoded);
    // FCA5063AEA0448C598B836FE05330AD4B6867BB9
}

Я предполагаю, что путаница в других комментариях закончилась, хотите ли вы предоставить лево-инверсию или право-инверсию.

То есть вам нужна функция "f", которая делает:

f(Decode(x)) == x // "left inverse"

or:

Decode(f(x)) == x // "right inverse"

Я предположил последнее, потому что вы сказали (1-й комментарий к другому ответу), что хотите иметь возможность воспроизвести кодировку Microsoft. (И что отметил Дин - ваша функция не обеспечивала обратимый вывод.) :)

В любом случае приведенное выше переопределяет вашу версию для правильного вывода, поэтому обе функции являются обратными друг другу.

person porges    schedule 28.06.2010
comment
Вы правы, я сократил байты в своем образце, он должен был быть FCA563AEA448C598B836FE533AD4B6867BB9, что показано в примере Дина, но никогда не объяснялось, как вы. Таким образом, X2 работает правильно, проблема заключалась в том, чтобы преобразовать строку в байты, чтобы их можно было использовать с Convert.ToBase64String. Спасибо, что объяснили мне мою ошибку доступным и конфронтационным способом. - person Rodney S. Foley; 28.06.2010
comment
@CG: это на один символ короче вашего исходного хэша... так что ему все еще не хватает нескольких байтов :) - person porges; 28.06.2010
comment
@Porges Я заметил, но пропустил окно для редактирования комментария, я обновил исходный вопрос правильным SHA1 (надеюсь;)) - person Rodney S. Foley; 28.06.2010
comment
@Isaac: пример до того, как я отредактировал, был из исходного хэша CG, в котором отсутствовали некоторые цифры :) - person porges; 28.06.2010
comment
@Porges, это более приятная реализация с использованием linq, сегодня утром я перешел на нее. - person Rodney S. Foley; 28.06.2010