Байты считываются как строка UTF8 и преобразуются в Base64.

Простите за длинную настройку здесь, но я подумал, что может помочь контекст...

Я реализую собственный метод проверки цифровой подписи как часть службы WCF. Мы используем специальный метод из-за различных интерпретаций некоторых отраслевых стандартов, но детали здесь не так важны.

В этом конкретном сценарии я получаю закодированный запрос MTOM/XOP, в котором корневая часть MIME содержит цифровую подпись, а части DigestValue и SignatureValue подписи разделены на отдельные части MIME.

Части MIME, которые содержат данные подписи DigestValue и SignatureValue, закодированы в двоичном формате, поэтому это буквально набор необработанных байтов в веб-запросе, например:

Content-Id: <[email protected]>
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary

[non-printable-binary-data-goes-here]
--uuid:eda4d7f2-4647-4632-8ecb-5ba44f1a076d

Я читаю содержимое сообщения в виде строки (используя кодировку UTF8 по умолчанию) следующим образом (см. параметр requestAsString ниже):

MessageBuffer buffer = request.CreateBufferedCopy(int.MaxValue);
try
{
    using (MemoryStream mstream = new MemoryStream())
    {
        buffer.WriteMessage(mstream);
        mstream.Position = 0;

        using (StreamReader sr = new StreamReader(mstream))
        {
            requestAsString = sr.ReadToEnd();
        }

        request = buffer.CreateMessage();
    }
}

После прочтения сообщения MTOM/XOP я пытаюсь реорганизовать несколько частей MIME в одно сообщение SOAP, в котором элементы подписи DigestValue и SignatureValue восстанавливаются в исходный конверт SOAP (а не в виде вложений). Итак, в основном я занимаюсь декодированием запроса MTOM/XOP.

К сожалению, у меня возникли проблемы с правильным чтением частей DigestValue и SignatureValue. Мне нужно прочитать байты из сообщения и получить строковое представление этих данных в формате base64.

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

Вот что я вижу в своем тестовом коде:

Это мой пример строки base64:

string base64String = "mowXMw68eLSv9J1W7f43MvNgCrc=";

Затем я могу получить байтовое представление этой строки. Это дает массив из 20 байтов:

byte[] base64Bytes = Convert.FromBase64String(base64String);

Затем я получаю версию этих байтов в кодировке UTF8:

string decodedString = UTF8Encoding.UTF8.GetString(base64Bytes);

Теперь странная часть... если я преобразую строку обратно в байты следующим образом, я получу массив байтов длиной 39 байтов:

byte[] base64BytesBack = UTF8Encoding.UTF8.GetBytes(decodedString);

Очевидно, что на данный момент, когда я конвертирую обратно в строку base64, она не соответствует исходному значению:

string base64StringBack = Convert.ToBase64String(base64BytesBack);

Для base64StringBack установлено значение «77+977+9FzMO77+9eO+/ve+/ve+/vVbvv73vv703Mu+/vWAK77+9».

Что я здесь делаю неправильно? Если я переключусь на использование UTF8Encoding.Unicode.GetString() и UTF8Encoding.Unicode.GetBytes(), все будет работать так, как ожидалось:

string base64String = "mowXMw68eLSv9J1W7f43MvNgCrc=";

// First get an array of bytes from the base64 string
byte[] base64Bytes = Convert.FromBase64String(base64String);

// Get the Unicode representation of the base64 bytes.
string decodedString = UTF8Encoding.Unicode.GetString(base64Bytes);

byte[] base64BytesBack = UTF8Encoding.Unicode.GetBytes(decodedString);

string base64StringBack = Convert.ToBase64String(base64BytesBack);

Теперь для base64StringBack установлено значение «mowXMw68eLSv9J1W7f43MvNgCrc=", поэтому кажется, что я каким-то образом неправильно использую кодировку UTF8 или она ведет себя не так, как я ожидал.


person BearsEars    schedule 07.04.2014    source источник


Ответы (2)


Произвольные двоичные данные не могут быть декодированы в строку в кодировке UTF8, а затем обратно закодированы в те же двоичные данные. Параграф «Недопустимые последовательности байтов» в http://en.wikipedia.org/wiki/UTF-8 указывает на это.

Я немного смущен тем, почему вы хотите, чтобы данные кодировались/декодировались как UTF8.

person Mikael    schedule 07.04.2014
comment
Мне нужно прочитать сообщение MIME, используя некоторую кодировку, верно? Как еще я мог бы проанализировать части MIME и выяснить, где начинается и заканчивается содержимое каждой части MIME? В этой ситуации у меня нет контроля над клиентской системой, отправляющей данные таким образом, иначе я бы сказал им, чтобы base64 кодировал двоичные данные в соответствующих частях MIME. - person BearsEars; 08.04.2014

Хорошо, я использовал другой подход к чтению сообщения MTOM/XOP:

Вместо того, чтобы полагаться на свой собственный код для ручного анализа частей MIME, я просто использовал XmlDictionaryReader.CreateMtomReader(), чтобы получить XmlDictionaryReader и прочитать сообщение в XmlDocument (стараясь сохранить пробелы в XmlDocument, чтобы цифровые подписи не нарушались). ):

MessageBuffer buffer = request.CreateBufferedCopy(int.MaxValue);

messageContentType = WebOperationContext.Current.IncomingRequest.ContentType;

try
{
    using (MemoryStream mstream = new MemoryStream())
    {
        buffer.WriteMessage(mstream);
        mstream.Position = 0;

        if (messageContentType.Contains("multipart/related;"))
        {
            Encoding[] encodings = new Encoding[1];
            encodings[0] = Encoding.UTF8;

            // MTOM
            using (XmlDictionaryReader reader = XmlDictionaryReader.CreateMtomReader(mstream, encodings, messageContentType, XmlDictionaryReaderQuotas.Max))
            {
                XmlDocument msgDoc = new XmlDocument();
                msgDoc.PreserveWhitespace = true;
                msgDoc.Load(reader);

                requestAsString = msgDoc.OuterXml;

                reader.Close();
            }
        }
        else
        {
            // Text
            using (StreamReader sr = new StreamReader(mstream))
            {
                requestAsString = sr.ReadToEnd();
            }
        }

        request = buffer.CreateMessage();
    }
}
finally
{
    buffer.Close();
}
person BearsEars    schedule 08.04.2014