【问题标题】:Sending a Password via TCP in C#在 C# 中通过 TCP 发送密码
【发布时间】:2011-12-06 14:49:57
【问题描述】:

我是一名程序员,所以基本上又是新手。

我正在做的是通过 Telnet 或 TCP 登录设备。我没有通过类型命令控制设备,而是使用自定义表单应用程序通过预编程的按钮发送类型字符串命令。该设备是旧的编解码器。我的软件的目的是创建一个可在 PC 上使用的按钮控制器。

我遇到的问题是我的一些设备受密码保护,而另一些则没有(不同的固件)。这是无法改变的。密码保护让我陷入了困境。

我正在使用 ASCII 向设备发送数据

public void Write(string cmd)
        {
            if (!tcpSocket.Connected) return;
            byte[] buf = System.Text.ASCIIEncoding.ASCII.GetBytes(cmd.Replace("\0xFF", "\0xFF\0xFF"));
            tcpSocket.GetStream().Write(buf, 0, buf.Length);

我一直在 MD5 上搜索并且卡住了。 我尝试通过在文本框中输入密码并启动写入命令的纯文本来发送密码。我也尝试过发送我在互联网上找到的这段代码的输出

public string EncodePassword(string originalPassword)
        {
            //Declarations
            Byte[] originalBytes;
            Byte[] encodedBytes;
            MD5 md5;

            //Instantiate MD5CryptoServiceProvider, get bytes for original password and compute hash (encoded password)
            md5 = new MD5CryptoServiceProvider();
            originalBytes = ASCIIEncoding.Default.GetBytes(originalPassword);
            encodedBytes = md5.ComputeHash(originalBytes);
            //Convert encoded bytes back to a 'readable' string
            return BitConverter.ToString(encodedBytes);                            

我什至发现了另一个强制大小写的 MD5 行。我不知道它是否不起作用,因为它仍在以 ASCII 或什么形式发送编码密码。

我知道我的密码是正确的,因为我可以在 Windows 中加载 telnet 并在那里正常登录。任何帮助让这个客户端通过服务器进行身份验证将不胜感激。


请原谅长度。由于我无法回复,我不得不编辑。我认为我对 MD5 感到困惑......阅读回复后,我认为我的问题是 ASCII。我需要纯文本。

好的,这就是我的初学者条纹闪耀的地方。这是我第一次尝试涉及任何类型的网络的编程(如果它还不是那么明显的话)。通过阅读回复,我认为我的第一个问题是 ASCII。我假设发送的是纯文本。鉴于当我使用不需要密码登录的同一客户端连接到服务器时...... ASCII 工作得很好。

如果我要使用纯文本,那么我将如何发送纯文本而不是字节转换?假设我假设 ASCII 是发送纯文本的方式是错误的......我现在认为它是。

我添加了更多代码来帮助解决这个问题。

使用 Windows telnet 客户端时,设备会提示输入密码,当您在 telnet 中输入密码时,直到登录后才会显示任何文本。登录后,所有输入都会立即显示。

用于套接字的类主要是我在谷歌上找到的一段代码。

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;

namespace STC_Control
{
    enum Verbs
    {
        WILL = 251,
        WONT = 252,
        DO = 253,
        DONT = 254,
        IAC = 255
    }

    enum Options
    {
        SGA = 3
    }

    class TelnetConnection
    {
        TcpClient tcpSocket;

        int TimeOutMs = 100;

        public TelnetConnection(string Hostname, int Port)
        {
            tcpSocket = new TcpClient(Hostname, Port);

        }

        public void WriteLine(string cmd)
        {
            Write(cmd + "\n");
        }

        public void Write(string cmd)
        {
            if (!tcpSocket.Connected) return;
            byte[] buf = System.Text.ASCIIEncoding.ASCII.GetBytes(cmd.Replace("\0xFF", "\0xFF\0xFF"));
            tcpSocket.GetStream().Write(buf, 0, buf.Length);
        }

        public string Read()
        {

            if (!tcpSocket.Connected) return null;

                StringBuilder sb = new StringBuilder();

                do
                {
                    ParseTelnet(sb);
                    System.Threading.Thread.Sleep(TimeOutMs);
                } while (tcpSocket.Available > 0);
                return sb.ToString();

        }

        public bool IsConnected
        {
            get { return tcpSocket.Connected; }
        }

        void ParseTelnet(StringBuilder sb)
        {
            while (tcpSocket.Available > 0)
            {
                int input = tcpSocket.GetStream().ReadByte();
                switch (input)
                {
                    case -1:
                        break;
                    case (int)Verbs.IAC:
                        // interpret as command
                        int inputverb = tcpSocket.GetStream().ReadByte();
                        if (inputverb == -1) break;
                        switch (inputverb)
                        {
                            case (int)Verbs.IAC:
                                //literal IAC = 255 escaped, so append char 255 to string
                                sb.Append(inputverb);
                                break;
                            case (int)Verbs.DO:
                            case (int)Verbs.DONT:
                            case (int)Verbs.WILL:
                            case (int)Verbs.WONT:
                                // reply to all commands with "WONT", unless it is SGA (suppres go ahead)
                                int inputoption = tcpSocket.GetStream().ReadByte();
                                if (inputoption == -1) break;
                                tcpSocket.GetStream().WriteByte((byte)Verbs.IAC);
                                if (inputoption == (int)Options.SGA)
                                    tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WILL : (byte)Verbs.DO);
                                else
                                    tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WONT : (byte)Verbs.DONT);
                                tcpSocket.GetStream().WriteByte((byte)inputoption);
                                break;
                            default:
                                break;
                        }
                        break;
                    default:
                        sb.Append((char)input);
                        break;
                }
            }

        }
    }
}

然后是程序

public Form1()
        {
            InitializeComponent();
        }
        //declorations
        TelnetConnection tc;
        Int16 vl = 13;


        private void connect_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(roomBox.Text))
            {
                MessageBox.Show("Please enter a selection before continuing");


            }
            else
            {
                {
                    try
                    {
                        //Connects to the server
                        tc = new TelnetConnection(roomBox.Text, 23);
                        //Enables controls
                        panelAll.Enabled = true;
                    }
                    catch
                    {
                        MessageBox.Show("Server Unreachable. ");
                        panelAll.Enabled = false;
                        cState.Text = "Disconnected";
                    }

                }
            }

// Button to send login password Temp created to test login
public void p_Click(object sender, EventArgs e)
        {
            try
            {
              //sends text to server  
              tc.WriteLine("PASSWORD");

              //enables Buttons
              panelAll.Enabled = true;

              //displays return to textbox to verify login or disconnect
              rx.Text = (tc.Read());
            }
            catch
            {
                panelAll.Enabled = false;
                MessageBox.Show("Communication with device was lost.");
                cState.Text = "Disconnected";
            }
        }

----------------------------------------------- -------------------------------------------------------

【问题讨论】:

  • 文本不显示是因为设备没有回显它,而不是因为有加密。如果它是一个纯粹的 telnet 接口,那么这无疑是个问题。以纯文本形式发送密码。 (耶!终于可以在任何地方发表评论了......多么烦人的“徽章”必须等待)。
  • 问题已解决。是客户端的协商协议有问题。

标签: c# .net networking telnet


【解决方案1】:

您的代码似乎有点不完整,无法给出完整的答案。如果可能,请提供从您的程序中剥离出来的更完整的逻辑流程。但据我所知,这里有一些即时提示......

  1. 不要将 MD5 与加密混淆。它们是非常非常不同的东西(MD5 是一种单向哈希,而加密是一种双向编码)。这可能是您头痛的根源。加密/散列握手方法必须由双方同意。如果您尝试使用密码的 MD5 哈希登录到仅接受纯文本密码的设备,则它不会将其识别为有效密码。对于这种情况,您实际上无能为力...必须是纯文本。
  2. 您认为密码是 ASCII 码?如果不是,ASCII 转换是个坏消息。这里可能不是根本问题,而是需要考虑的问题。

编辑:实际上......让我更深入地了解,因为经过进一步思考,我大约 90% 确定这是您的问题(当然没有更多信息)。

处理仅支持纯文本密码的设备时的逻辑流程是这样的(其中 C 是客户端 [你],S 是服务器 [他们])...

[C] Send password plain-text
[S] Got your password, thanks! I just checked it against what I know and it's good/bad

当使用任何类型的散列时。

[C] Hash password (MD5, SHA1, etc)
[C] Send password
[S] Receive hash of password. Check against hashed password stored (or worse, hash of plain-text password stored). Respond good/bad

加密连接时(当客户端和服务器知道它们都使用哪种加密时)......

[C] Garble-garble-garble (password encrypted)
[S] Got it... and garble-garble-garble turns into whatever plain-text password. Checked it against local storage and .... garble-garble-garble (good/bad encrypted)

加密连接时(客户端/服务器可能不一定支持相同的方法,但知道如何协商使用哪个)...

[C] Which encryption methods do you support? Here's my list...
[S] Oh, well, we both support these methods. Which do you want to use?
[C] IDEA sounds good.
[S] Sounds good to me too. Start using it.
[C] Garble-garble-garble (password encrypted)
[S] Got it... and garble-garble-garble turns into whatever plain-text password. Checked it against local storage and .... garble-garble-garble (good/bad encrypted)

如您所见,方法非常不同。这些必须内置到通信设备(服务器)中才能成功协商。

【讨论】:

  • 抱歉,我还不能直接评论你更改的帖子,但是是的......我真的很确定你不应该试图对你的 MD5 哈希密码。您的目标设备很可能支持加密或散列。因此,您必须以纯文本形式发送密码。您的逻辑似乎确实没有任何问题,但交流的方式并不真正可用。尽量不要散列你的,让我知道它是否有效。
  • 哦,ASCII 不是你的问题。它只是一个 7 位编码标准(草率处理程序为 8 位),为您转换它的类正在将文本剥离为 7 位等效项,在您的情况下,这可能甚至不明显(因为大多数基本的拉丁字符直接映射到 ASCII)。我只是第一次指出它,因为它假设了很多关于字符编码的内容。这表明现代应用程序存在潜在问题。 Google 字符集、unicode 等。这只是一个通用提示,提醒您以 a-z 为中心的世界并非真实世界。
【解决方案2】:

我不认为这是一个编程问题。我相信这更多的是了解您的设备如何实际工作的问题。它接受纯文本形式的密码,还是接受某种散列或加密形式的密码?

您可以通过 telnet 提供密码这一事实表明它是纯文本的,除非 telnet 协议规定了某些身份验证。

如果您能提供 telnet 窗口的屏幕截图就更好了。我们或许可以从中得到一些提示。

我建议您提交纯文本密码,后跟 \n 换行符。

【讨论】:

    【解决方案3】:

    在我看来,您最好的解决方案是下载 OpenSSL 包,将其安装在设备和表单应用程序上,然后使用 API 使用安全 shell 连接而不是 telnet 来发送设备命令。

    这样,密钥管理就在您的应用之外,您可以使用预先编写的 API 在经过测试的代码中进行加密。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-10
      • 1970-01-01
      • 2013-07-21
      • 1970-01-01
      • 1970-01-01
      • 2018-04-12
      • 1970-01-01
      相关资源
      最近更新 更多