在 C# 中通过 TCP 发送密码
我是一名经验丰富的程序员,所以基本上又是新手。
我正在做的是通过 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";
}
}
-------------------------------------------------------- -------------------------------------------
I'm and out of practice programmer, so basically new to it again.
What I am doing is logging onto a a device over Telnet or TCP. Instead of controlling the device by type command I am using a custom forms application to send the type string commands by pre programmed push button. The device is an old Codec. The purpose of my software is to create a push button controller to be used from a PC.
The problem I am having is that some of my devices are password protected and some are not (different firmware). This cannot be changed. The Password protection is what has me stuck.
I am sending data to the device using 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);
I have been searching on MD5 and have become stuck.
I have tried sending the password by plain text typing the password into a text box and initiating the write command. I have also tried sending the output of this code I found on the internet
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);
I even found another MD5 line that forced upper and lower case. I don't know if it wont work because it is still sending the encoded password in ASCII or what.
I do know that my password is right because I can load telnet in windows and log on fine there. Any help in getting this client to authenticate with the server would be most appreciated.
Forgive the length. Since I am unable to reply I had to edit. I think that I was confused on the MD5... After reading the replies I think my problem is the ASCII. I need plain text.
Ok, so this is where my beginner stripes shine brightly. This is my first attempt at programming that involves a network of any sort (if it wasn't already that obvious). From reading the replies I think my first problem is the ASCII. I assumed that being sent though that was plain text. Given that when I connect to a server with the same client that does not require password login... The ASCII works just fine.
So if I am to use plain text, then How would I go about sending in plain text and not a byte conversion? Assuming that my assumption that ASCII was the way to send plain text is wrong...Which I now think that it is.
I have added more code to help this along.
When using the Windows telnet client, the device prompts for password and when you type it into telnet no text is shown until after login. After login all typing is shown immediately.
The Class used for the socket is mostly a code I found on google with some small tweeks.
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;
}
}
}
}
}
Then the program
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";
}
}
------------------------------------------------------------------------------------------
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的代码似乎有点不完整,无法给出完整的答案。如果可能的话,提供从程序中剥离出来的更完整的逻辑流程。但据我所知,这里有一些直接的提示...
编辑:实际上......让我更深入地了解一下,因为经过进一步思考,我大约 90% 确定这是你的问题(当然没有更多信息)。
处理仅支持纯文本密码的设备时的逻辑流程是这样的(其中 C 是客户端 [您],S 是服务器 [他们])...
当使用任何类型的哈希时。
当加密连接时(当客户端和服务器知道它们都使用哪种加密时)...
当加密连接时(并且客户端/服务器可能不一定支持相同的方法,但知道如何协商使用哪种方法)...
正如您所看到的,方法非常不同。这些必须内置到通信设备(服务器)中才能成功协商。
Your code seems a bit incomplete to give a full answer. If possible, supply a more complete flow of logic stripped out of your program. But from what I can gather, here's some immediate tips...
EDIT: Actually... let me go more into depth because after further thought, I'm about 90% sure this is your problem (without more information of course).
The flow of logic when dealing with a device that only supports plain-text passwords is this (where C is client [you] and S is server [them])...
When using any kind of hashing.
When encrypting the connection (when client and server know what kind of encryption they both use)...
When encrypting the connection (and the client/server may not necessarily support the same methods but know how to negotiate which to use)...
As you can see, very different methods. Those must be built into the communication device (server) for a successful negotiation.
我不认为这是一个编程问题。我认为这更多的是了解您的设备实际工作原理的问题。它接受纯文本形式的密码,还是接受某种散列或加密形式的密码?
事实上,您可以通过 telnet 提供密码,这表明它是纯文本,除非 telnet 协议提供了某些身份验证的规定。
如果您能提供 telnet 窗口的屏幕截图就更好了。我们或许可以从那里得到一些提示。
我建议您提交纯文本密码,后跟 \n 换行符。
I don't think this is a programming problem. I believe it's more of a problem of understanding how your device actually works. Does it accept password as plain text, or does it accept password in some hashed or encrypted form?
The fact that you can provide the password through telnet suggest that it is plain text, unless the telnet protocol has provision for some for of authentication.
It would be good if you could provide a screenshot of the telnet window. We might be able to get some hints from there.
I would recommend that you submit the plain text password followed by the \n new line character.
在我看来,最好的解决方案是下载 OpenSSL 软件包,将其安装在设备和表单应用程序上,然后使用 API 来使用安全 shell 连接而不是 telnet 来发送设备命令。
这样,密钥管理就在您的应用程序之外,您可以使用预先编写的 API 在经过测试的代码中进行加密。
It sounds to me that your best solution here would be to download the OpenSSL package, install it on the device and your forms app, and then use the APIs to use a secure shell connection instead of telnet to send device commands.
That way the key management is outside your app and you can use prewritten APIs to do your encryption in a tested piece of code.