原谅这里冗长的设置,但我认为这可能有助于获得背景......
我正在作为WCF服务的一部分实现自定义数字签名验证方法。我们正在使用自定义方法,因为对某些行业标准有各种不同的解释,但细节并非全部相关。
在这个特定场景中,我收到一个MTOM / XOP编码请求,其中根MIME部分包含数字签名,签名DigestValue和SignatureValue部分被分成单独的MIME部分。
包含签名DigestValue和SignatureValue数据的MIME部分是二进制编码的,因此它在Web请求中实际上是一堆原始字节,如下所示:
Content-Id: <c18605af-18ec-4fcb-bec7-e3767ef6fe53@example.jaxws.sun.com>
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设置为&#34; 77 + 977 + 9FzMO77 + 9eO + / ve + / ve + / vVbvv73vv703Mu + / vWAK77 + 9&#34;
我在这里做错了什么?如果我切换到使用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设置为&#34; mowXMw68eLSv9J1W7f43MvNgCrc =&#34;所以我似乎错误地使用了UTF8编码,或者它的行为与我预期的不同。
答案 0 :(得分:2)
任意二进制数据无法解码为UTF8编码字符串,然后编码回相同的二进制数据。段落&#34;无效的字节序列&#34;在http://en.wikipedia.org/wiki/UTF-8点出来。
我对为什么要将数据编码/解码为UTF8感到有点困惑。
答案 1 :(得分:0)
好的,我采用了不同的方法来阅读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();
}