3

我有一个问题,我试图以 base64 格式发送数据。来自客户端的发送效果很好。但是,如果我试图在服务器上反编译 base64,我仍然总是出错,base64 字符无效。

我正在寻找一种方法,将数据从客户端加密到服务器并在服务器上解密,以实现安全传输。

我的代码显示 atm 是这样的: 客户:

socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect(ipAddress, ipAddressPort, new AsyncCallback(testA), null);

protected static void testA (IAsyncResult ar) {
      socket.EndConnect(ar);
      string str = EncodeTo64("Hello world!");
      socket.BeginSend(System.Text.Encoding.UTF8.GetBytes(str), 0, str.Length, SocketFlags.None, new AsyncCallback(testB), socket);
    }
    protected static void testB (IAsyncResult ar) {
      socket.EndSend(ar);
      socket.BeginReceive(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(testC), socket);
    }
    protected static void testC (IAsyncResult ar) {
      socket.EndReceive(ar);
      MessageBox.Show(System.Text.Encoding.UTF8.GetString(bytes));
    }
    static public string EncodeTo64(string toEncode)
    {
      byte[] toEncodeAsBytes
            = System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
      string returnValue
            = System.Convert.ToBase64String(toEncodeAsBytes);
      return returnValue;
    }
    static public string DecodeFrom64(string encodedData)
    {
      byte[] encodedDataAsBytes
          = System.Convert.FromBase64String(encodedData);
      string returnValue =
         System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes);
      return returnValue;
    }

服务器:

serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 4444);

serverSocket.Bind(ipEndPoint);
serverSocket.Listen(4);


serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);

 protected static byte[] byteData = new byte[1024];
private void OnAccept(IAsyncResult ar)
    {
      Socket clientSocket = serverSocket.EndAccept(ar);

      //Start listening for more clients
      serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);

      //Once the client connects then start receiving the commands from her
      // Create the state object.
      clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None,
           new AsyncCallback(OnReceive), clientSocket);
    }

private void OnReceive(IAsyncResult ar) {
      Socket clientSocket = (Socket)ar.AsyncState;
      clientSocket.EndReceive(ar);
MessageBox.Show(DecodeFrom64(System.Text.Encoding.UTF8.GetString(byteData)));
}
    static public string EncodeTo64(string toEncode)
    {
      byte[] toEncodeAsBytes
            = System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
      string returnValue
            = System.Convert.ToBase64String(toEncodeAsBytes);
      return returnValue;
    }
    static public string DecodeFrom64(string encodedData)
    {
      byte[] encodedDataAsBytes
          = System.Convert.FromBase64String(encodedData);
      string returnValue =
         System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes);
      return returnValue;
    }
    public void OnSend(IAsyncResult ar) {
      Socket client = (Socket)ar.AsyncState;
      client.EndSend(ar);
    }
4

1 回答 1

2

正如 Marc Gravell 所写,您不必要地使网络协议复杂化。网络传输本质上是复杂的,所以避免任何不必要的复杂化!

当他说你必须确保你真的阅读了所有发送的数据时,他也是绝对正确的。请查看文档和那里的示例(尤其是Socket 类Socket.EndReceive;请注意,只是调用EndReceive不足以确保所有内容都已阅读)。要点是:您需要在服务器端有一个循环,以确保已读取所有发送数据。如果要发送的数据很简单并且网络非常可靠(阅读:通过电缆的本地以太网,没有 WiFi;互联网,尤其是移动互联网不可靠),也许只是一个循环直到没有更多数据到达可能就足够了;在任何更复杂的场景中,使用 Marc 建议的框架协议会更明智,这将提供一种更可靠的方式来决定何时结束阅读循环。

您可以使用以下代码轻松重现您的错误:

var data = Encoding.ASCII.GetBytes("Hello World!");
var base64 = Convert.ToBase64String(data);
var bytesToSend = Encoding.UTF8.GetBytes(base64);
var stringRecieved = Encoding.UTF8.GetString(bytesToSend).Substring(0, 5);
var decoded = Convert.FromBase64String(stringRecieved);
var result = Encoding.ASCII.GetString(decoded);
Console.WriteLine("{0} -> {1} -> {2}", base64, stringRecieved, result);

模拟.Substring(0, 5)尚未完全读取的网络流。如果你删除.Substring然后一切正常。为了支持 Marcs 点,以下内容足以发送数据:

var bytesToSend = Encoding.UTF8.GetBytes("Hello World!");
var stringRecieved = Encoding.UTF8.GetString(bytesToSend);

另一个重要说明:BASE64 与加密完全无关。它只是一种编码,如 UTF8 或 ASCII。如果您需要安全的通信通道,BASE64 不是解决方案!如果窃听者读取了您的 BASE64 编码消息,他可以轻松识别编码,然后对其进行解码。

如果您需要安全通道,请使用 AES 等强加密标准或使用 TLS 等安全网络协议(例如通过 HTTPS;使用 HTTPS 还可以解决 Marc Gravell 提到的用于更复杂数据交换的“框架”问题)。

于 2012-07-28T09:10:17.917 回答