c# - 在不知道字节数的情况下读取特殊流

标签 c# ssl stream bouncycastle

在你去之前说使用Jon Skeet's answer ,我不能。 我是using this stream一开始很好,但现在,我遇到了一个小问题。我现在不知道我期望的数据量,所以我想我会使用 Jon Skeet 提供的方法,但不幸的是它等待 packet = mPackets.Take()当所有数据包都被读取时。

我不知道如何解决这个问题,流会做它应该做的(在开始时),但不幸的是,这是我不希望它做它为...做的事情的场合......

我应该尝试重写 waitingstream 还是有不同的 readall 方法更适合我的情况?

我曾尝试在没有更多数据包可用时返回 0(当我希望它读取所有数据而不是等待时),但随后它抛出一个 IO 流结束异常

我真的很茫然,我明白我给自己挖了一个深坑......

到目前为止,我还没有想出比从总长度中减去 TLS header 和 GCM IV 和 MAC 更好的解决方案(如下所述)这适用于我现在使用的 1 个套件,但确实不能为 future 的密码套件吹嘘。


关于我为什么这样做的一些背景:
我正在使用 https://github.com/bcgit/bc-csharp创建基于 TLS 的加密,但是由于限制我无法为其分配 TCP 流,我得到的只是来自 TCP 层的字符串,我无法为其提供适当的 TCP 流。

我正在使用 mockPskTlsServer and client我是这样创建的:

WaitingStream mStdin = new WaitingStream();
WaitingStream mStdout = new WaitingStream();
CryptoPskTlsClient mServer = new CryptoPskTlsClient(null);
SecureRandom secureRandom = new SecureRandom();
TlsClientProtocol TlsProtocol = new TlsServerProtocol(Stdin, Stdout, secureRandom);
TlsProtocol.Connect(mServer);

这很好用,我还在等待流中添加了一个事件,该事件在流有输出时触发。这样我就可以在创建时获得多个握手消息。

这一切都很好,可以做得更好(更少......被黑客入侵?)但它做了它应该做的事情。

我确实知道让它工作的方法,但这是一个 HACK,我正在寻找一种优雅的方法来做到这一点。这是其中一个 HACKS 的代码示例:

public override string DecryptData(string ciphertext)
{
    byte[] ciphertextBuff = ASCIIEncoding.Default.GetBytes(ciphertext);
    mStdin.Write(ciphertextBuff, 0, ciphertextBuff.Length);

    Stream tlsStream = mServerProtocol.Stream;
    byte[] plaintextBuffer = new byte[ciphertextBuff.Length - 29];//filthy HACK 29 bytes bij AES-GCM want TLS packet = 5, GCM IV = 8, GCM-MAC = 16 totaal = 29.
    Streams.ReadFully(tlsStream, plaintextBuffer);

    string plaintext = ASCIIEncoding.Default.GetString(plaintextBuffer);
    return plaintext;
}

或者通过将 x 个保留字节中的明文长度添加到 TLS 数据包并在解密之前检索这些字节。

但是从代码示例中可以清楚地看到,完全读取方法中的缓冲区必须是我要提取的字节长度,它可以小于流的长度,但不能大于,因为那样它会等待无限期。

当我谈论像 ReadAllReadFully 这样的方法时 I mean these methods

最佳答案

all i get is a string from the TCP layer

这肯定是您尝试使这项工作的致命缺陷。您正在尝试做的隐含是通过 TCP 连接发送的数据是 TLS 加密的。这会产生高度随机的字节值,0 到 255 之间的任何值都是可能的。您将从套接字的 Read() 调用接收到的数据包是 byte[],而不是字符串。

将 byte[] 转换为字符串需要使用 .NET Encoding 类。它有很多种,常用的有ASCIIEncoding、UnicodeEncoding、UTF8Encoding。还有一些设计用于特定代码页的自定义代码,您可以使用 Encoding(int codePage) 构造函数来获取它们。

我们不知道您需要使用的“TCP 层”使用什么编码,可能是 UTF8,但可以肯定的是,当它被要求转换字节时,它总是会产生损坏的数据[ ] 与加密内容。某些字节值没有相应的 Unicode 代码点。编码对象通过生成 ? 作为替代字符来解决此类问题。无论 Encoding.EncoderFallback 的值是什么。您有可能在调试器中看到它们,尽管频率不可预测。

换句话说,加密数据将不可避免地被这些替换破坏。对此没有解决方法,您无法恢复原始 byte[],因为内容因替换而丢失。这必须由下层解决,他们要么需要将 byte[] 内容编码为始终可以转换的字符串(base64 是标准解决方案),要么需要停止将数据转换为字符串。您确实需要原始 byte[] 才能完成这项工作。

关于c# - 在不知道字节数的情况下读取特殊流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30638147/

相关文章:

Unix/Linux 上的 C# 开发(有人用过 CoreFX 吗?)

Node .js : how to pipe - youtube to mp4 to mp3

尽管管道坏了,Bash 并没有结束循环

c# - 如何实现一个通用的c#接口(interface)

c# - AWS Systems Manager 参数存储 : Lambda function hangs

c# - Javascript不获取隐藏文本框值?

docker - 在Dockerfile中应用CA根证书

Django 在 HTTPS 上显示 500 内部服务器错误

c# - 相同的 url 不同的环境 - 一个成功另一个失败并出现 SSL 错误

C++ 将值解析为 vector 的更好方法