通过加密来保护您的即时消息( IM) 对话






4.63/5 (25投票s)
2005年10月20日
6分钟阅读

156494

2767
了解如何加密即时通讯 (IM) 对话。
IMEncryptor: 加密您的即时通讯 (IM) 对话。
图 1. 全景图。
目录
- 引言
- 特点
- 必备组件
- 拼图碎片,或者说……我们在玩什么?
- 想法 - 用文字描述
- 三个窗口区域。
- 发送加密的消息行。
- 解密加密的入站消息。
- 想法 - 用代码描述
- 查找我们感兴趣的三个窗口区域的 HWND。
- 发送加密的消息行。
- 解密加密的入站消息。
- 如何使用 IMEncryptor
- 待办事项列表
- 版本历史
引言
如今,每个人都知道如何使用 嗅探器,并且可能(如果通道尚未加密)找到一些敏感信息。将此类工具“隐藏”在网络内部的几个敏感区域,“潜伏”起来,有人可能会截获例如 Yahoo Messenger 的对话。这是因为(您可能知道这个事实)这些对话并未加密。
短故事
早在 2000 年,曾有一个 Yahoo Messenger 企业版。该版本使用加密来保护对话。由于大公司没有购买它(因为它不是免费的),三年后,Yahoo 解散了其企业解决方案部门。
回到我们的工具,您该如何保护自己?
- 有一些 软件套装 可供选择,但是……您必须购买它们。
- 尝试找出加密对话行的可能方法。这就是我当时的想法……
特点
- 使用 Yahoo Messenger 与朋友发送(接收)的文本消息的加密(解密)。
- 这个初始版本(1.0 版)仅支持 3DES 加密算法。
- 加密的消息会用星号 (*) 标记。
- 保存在您硬盘上的消息(消息存档)将保持加密状态。消息会在您启动应用程序时解密。
图 2. 消息存档。
必备组件
- Visual Studio 2005 Express Edition Beta 2(或 Visual Studio 2005 Team System Beta 2)。
- Yahoo Messenger 7.0.
- .NET Framework 2.0 Beta Redistributable.
- 一个“安全私密通道”:) 用于与朋友交换秘密密码(稍后将提供支持密钥交换的版本)。
拼图碎片,或者说……我们在玩什么?
- 底层 Windows 消息(嗯……现在非常底层 - 只使用旧的 WM_* 消息)。
- .NET 加密。
想法 - 用文字描述
正如您所见,Yahoo Messenger 窗口被划分为几个区域。这些区域就是窗口,每个窗口都有一个 hWnd
(窗口句柄)。其他 Windows 软件套装不使用这种技术(例如,Office 套件)。为每个控件使用窗口句柄会消耗系统资源。在我们的案例中,这些句柄将帮助我们实现目标。
我们感兴趣的三个窗口区域是:
- 您键入要发送的消息的区域 - WriteArea。
- 显示与朋友发送/接收的消息的区域 - TalkArea。
- 我们点击发送这些消息的按钮 -
SendButton
。
图 3. 窗口区域。
接下来,您将看到加密消息、发送加密消息以及解密收到的加密消息所需的步骤。
发送加密的消息行
- 从编写区域剪切消息 -
hWndWriteArea
。 - 使用我们的应用程序加密它。
- 粘贴回编写区域,标记为待解密 -
hWndWriteArea
。 - 通过模拟点击“发送”按钮发送它 -
hWndSendButton
。
解密加密的入站消息
- 从对话区域获取消息 -
hWndTalkArea
。 - 检查消息是否有标记。
- 解密标记的消息。
- 将这些消息粘贴回对话区域 -
hWndTalkArea
。
想法 - 用代码描述
查找我们感兴趣的三个窗口区域的 HWND
检查前台窗口是否为 Yahoo Messenger 对话窗口。如果是,则调用 MessengerYahoo_HandleWindow
方法。此方法通过调用 MessengerYahoo_MoveTheWindow
将 IMEncryptor 窗口移动到对话窗口旁边,然后使用委托,它会遍历子窗口以查找我们感兴趣的 hWnd
,即 MessengerYahoo_HandleEnumChild
。
提示:如果您想再次搜索子窗口,此函数应返回 true
;否则,则返回 false
。
private bool MessengerYahoo_HandleEnumChild(
IntPtr hWnd, IntPtr lParam)
{
int textLength = Win32API.SendMessage(hWnd,
Win32API.WM_GETTEXTLENGTH, 0, IntPtr.Zero);
StringBuilder text = new StringBuilder(textLength + 1);
Win32API.SendMessage(hWnd, Win32API.WM_GETTEXT,
textLength + 1, text);
StringBuilder className = new StringBuilder();
Win32API.GetClassName(hWnd, className,
className.MaxCapacity);
if (className.ToString().Contains(writeAreaClassName))
hWndWriteArea = hWnd;
if (className.ToString().Contains(talkAreaContainerName))
hWndTalkArea = Win32API.FindWindowEx(hWnd,
IntPtr.Zero, talkAreaClassName, IntPtr.Zero);
if (className.ToString().Contains(sendButtonClassName))
if (text.ToString().Contains(sendButtonText))
hWndSendButton = hWnd;
if ((hWndWriteArea == IntPtr.Zero) ||
(hWndTalkArea == IntPtr.Zero) ||
(hWndSendButton == IntPtr.Zero))
return true;
else
return false;
}
writeAreaClassName
、talkAreaContainerName
、talkAreaClassName
、sendButtonClassName
和 sendButtonText
在 FrmMain
类的开头处的 Variables
和 Constants
区域中定义。
#region Variables and Constants
IntPtr hWndForegroundWindow; // Foreground window handler
IntPtr hWndTalkArea; // Talk area window handler
IntPtr hWndWriteArea; // Write area window handler
IntPtr hWndSendButton; // Send button window handler
// Yahoo Messenger's window title contains this string
const String windowTitle = "- Instant Message";
// The class name of the writeArea zone
const String writeAreaClassName = "YIMInputWindow";
// The container name of the "talkArea"
const String talkAreaContainerName = "YHTMLContainer";
// The class name of the "talkArea"
const String talkAreaClassName = "Internet Explorer_Server";
// The class name of the "sendButton"
const String sendButtonClassName = "Button";
// The text of the "sendButton"
const String sendButtonText = "&Send";
// Marks the START of an encrypted line of message
const String startTag = "!%";
// Marks the END of an encrypted line of message
const String stopTag = "%!";
// This is a decrypted line
const String decryptedLineMarker = "* ";
// The secret password entered by the user
static String secretPassword;
#endregion
发送加密的消息行
FrmMain
类中的 MessengerYahoo_HandleSend
方法处理此问题。如您在下面的代码中所示:
- 我们发送
Win32Api.WM_GETTEXTLENGTH
来获取hWndWriteArea
后面的窗口文本的长度,并发送Win32Api.WM_GETTEXT
消息来获取明文消息。 - 初始化并使用对称加密提供程序
SIMCrypto
(3DES),通过调用sc.Encrypt
来加密明文消息。 - 使用
Win32API.WM_SETTEXT
将消息写回hWndWriteArea
后面的窗口。 - 通过模拟点击发送按钮来发送加密的消息(我们向按钮发送
Win32API.BN_CLICK
消息)。
提示:通过调用 Win32API.SetForegroundWindow
将前台窗口设置回原位,用户就可以开始键入另一条消息了。
private void MessengerYahoo_HandleSend()
{
// 1. GET the message from the writeArea
int textLength = Win32API.SendMessage(hWndWriteArea,
Win32API.WM_GETTEXTLENGTH, 0, IntPtr.Zero);
StringBuilder writingtext =
new StringBuilder(textLength + 1);
Win32API.SendMessage(hWndWriteArea,
Win32API.WM_GETTEXT, textLength + 1, writingtext);
// 2. ENCRYPT the message
SIMCrypto sc =
new SIMCrypto(SIMCrypto.ServiceProviderEnum.TripleDES);
String encryptedText = startTag +
sc.Encrypt(writingtext.ToString(), secretPassword) +
stopTag;
// Delete the message from the writeArea
Win32API.SendMessage(hWndWriteArea,
Win32API.WM_SETTEXT, 0,
System.Text.Encoding.ASCII.GetBytes("".ToCharArray()));
// 3. PASTE the new encrypted message
byte[] encryptedText_byte =
System.Text.Encoding.ASCII.GetBytes(
encryptedText.ToCharArray());
Win32API.SendMessage(hWndWriteArea,
Win32API.WM_SETTEXT, 0, encryptedText_byte);
// 4. SEND the new encrypted message
// (by simulating a click on the Send button)
Win32API.SendMessage(hWndSendButton,
Win32API.BM_CLICK, 0, encryptedText_byte);
// Delete the message from the writeArea
Win32API.SendMessage(hWndWriteArea,
Win32API.WM_SETTEXT, 0,
System.Text.Encoding.ASCII.GetBytes("".ToCharArray()));
// Set the foreground window = the messeger window
Win32API.SetForegroundWindow(hWndForegroundWindow);
}
解密加密的入站消息
FrmMain
类中的 MessengerYahoo_HandleDecryption
方法处理此问题。如您在下面的代码中所示:
- 我们通过向
hWndTalkArea
发送WM_HTML_GETOBJECT
消息来获取IHTMLDocument2
的句柄。IHTMLDocument2
被“Internet Explorer_Server”控件封装,该控件在上方定义为talkAreaClassName
。一篇关于此问题的小而有趣的短文可以在此处找到。 - 接下来,我们(以一种简单的方式)解析其结构以获取标记的消息。
- 使用相同的加密提供程序
SIMCrypto
(3DES)并通过调用sc.Decrypt
方法解密标记的消息。 - 将解密的消息粘贴回其应在的位置。
提示:要能够使用 IHTMLDocument2
,您需要添加对名为 Microsoft.mshtml
的 .NET 组件的引用。
private void MessengerYahoo_HandleDecryption()
{
// 1. GET the messages from the conversation area
uint msg =
Win32API.RegisterWindowMessage("WM_HTML_GETOBJECT");
IntPtr lRes = IntPtr.Zero;
Win32API.SendMessageTimeout(hWndTalkArea, msg,
IntPtr.Zero, IntPtr.Zero,
Win32API.SendMessageTimeoutFlags.SMTO_ABORTIFHUNG,
1000, out lRes);
IHTMLDocument2 myHTMLDoc =
(mshtml.IHTMLDocument2)Win32API.ObjectFromLresult(lRes,
typeof(mshtml.IHTMLDocument).GUID, IntPtr.Zero);
foreach (IHTMLElement el in (IHTMLElementCollection)myHTMLDoc.body.all)
if ((el.GetType().ToString().
CompareTo("mshtml.HTMLSpanElementClass") == 0) &&
(el.className != null))
// 2. CHECK for the markers
if ((el.innerText != null) &&
(el.innerText.IndexOf("!%") >= 0) &&
(el.innerText.LastIndexOf("%!") > 0))
{
// 3. DECRYPT the marked message
String ts = el.innerText.ToString();
String ts2 = ts.Substring(el.innerText.IndexOf(startTag) + 2,
el.innerText.LastIndexOf(stopTag) - 2);
String decryptedText = null;
try
{
SIMCrypto sc =
new SIMCrypto(SIMCrypto.ServiceProviderEnum.TripleDES);
decryptedText =
decryptedLineMarker + sc.Decrypt(ts2, secretPassword);
}
catch (Exception ex)
{
decryptedText =
"\n" + "Received a malformed encrypted string:" +
ts2 + "\n" + "Exception generated: " + ex.Message;
}
// 4. PASTE the decrypted message
el.innerText = decryptedText;
}
}
如何使用 IMEncryptor
- 下载并安装 .NET Framework 2.0 Beta 2(如果尚未安装)。
- 下载并运行 IMEncryptor.exe 文件(您可以在 IMEncryptor_Demo.zip 中找到它)。
- 启动 IMEncryptor,在文本框中输入您的秘密密码,然后勾选“启用加密”复选框。
- 启动 Yahoo Messenger 对话窗口。您会看到 IMEncryptor 窗口停靠在当前对话窗口旁边。
- 在编写区域键入一条消息,键入后不要按回车键。点击“发送加密消息”按钮。
- 如果您喜欢或不喜欢这个程序,发现错误,或者想要实现其他功能,请给我发消息(或电子邮件)。
待办事项列表
- 进一步优化代码。
- 支持多种加密算法。
- 自动密钥交换机制。
- 管理多个密钥(针对多个用户)。
- 启用全局钩子以捕获 Enter 键?
- 支持其他即时通讯软件(MSN Messenger、Google Talk 等)?
- 您来命名功能……
版本历史
- 2005 年 10 月 20 日 - 1.0 版。
- 首次发布。包含主要功能。