基于Python语言、RSA非对称加密的IRC聊天室客户端

1 篇文章 0 订阅
1 篇文章 0 订阅

源码地址:

(55条消息) 基于Python语言、RSA非对称加密的IRC聊天室客户端源码与应用程序-Python文档类资源-CSDN文库

1 研究背景和现状

IRC是Internet Relay Chat 的英文缩写,中文一般称为互联网中继聊天。它是由芬兰人Jarkko Oikarinen于1988年首创的一种网络聊天协议。经过十年的发展,目前世界上有超过60个国家提供了IRC的服务。IRC的工作原理非常简单,您只要在自己的PC上运行客户端软件,然后通过因特网以IRC协议连接到一台IRC服务器上即可。它的特点是速度非常之快,聊天时几乎没有延迟的现象,并且只占用很小的带宽资源。所有用户可以在一个被称为\"Channel\"(频道)的地方就某一话题进行交谈或密谈。每个IRC的使用者都有一个Nickname(昵称)。

IRC用户使用特定的用户端聊天软件连接到IRC服务器,通过服务器中继与其他连接到这一服务器上的用户交流,所以IRC的中文名为"因特网中继聊天"。

IRC的最大特点是实现了在线实时交谈,速度快、功能多的优点使它比电子邮件或新闻组等联络沟通方式更具吸引力。IRC可以设置单独的频道,在这个频道内,输出的文字可供所有人都看到。这样,来自世界不同角落的人能同时得到有关信息。而如果是两个人之间的单独交谈,甚至可以不用通过服务器,以保证谈话的保密性。随着网络带宽的增加和技术的发展,现在有一些IRC不仅可以传输文字信息,还能传输声音或图像信息,这样的功能就更强了。

2 研究历史和现状

在网上我们查到了这样一段话,认为能够很好地概括IRC的发展与现状:

因为本人研究IRC时间较长,鉴于目前的发展状况,近两年来都有如下的思考。

目前IRC也仅有263还算是IRC了,但它也仅是人数上处于一个领先的地位,从其发展与聊天人群来看,已经再也不是2000-2002年的IRC了。从2000年来看,sina,sohu,tom,163,几乎所有大网站的web聊天室都是基于IRC的,为什么就突然不行了呢?

其实我认为IRC到目前为止,还是一个很好的东西,只不过它固有模式不适合在中国发展。由于游戏产业的突飞猛进以及qq,msn等音视频支持的即时通信工具的出现,IRC在一夜之间跌入低谷,从此原本喜欢IRC的用户一下子分流到其它工具之上。而提供IRC服务的服务商们也没有精力继续维持,直接导致了现在这个窘况的出现。

我认为,IRC在中国的应用应该转变它的角色了,如果再将它做为一个聊天服务来提供的话是肯定不行的。但它优秀的网络结构及传输协议还是可以扩展到其它行业去的。因为现有很多行业或是网站它需要的一个用户与服务器的长连接来实现适时数据的交换,这个时候,IRC还是很有用途的。比如说网站的在线客户服务系统(目前已有公司专门提供了),基于即时通讯的电子商务(alibaba已经走在前头了,当我有此想法的时候,alitalk也没有出现),网络与现场相结合的拍卖系统等,很多的应用都可以用IRC来实现,但这就需要我们对IRC的服务器端及协议要有非常熟悉的了解,还需要我们能写出自已的客户端软件或是web applet、flash等web客户端。其实用扩展IRC server协议写出基于flash的网络休闲游戏都是有可能的。当然由于IRC协议的纯文本发送模式的限制,它不可以用在保密性要求较高的项目中。  所以,我还是相信IRC会有它的用武之地。当然我也只是研究研究罢了,没有超前的商业头脑去想出一个什么好的产品投入应用,如果你有更好的应用项目,那就告诉我吧,也许我可以帮你实现。

综上所述:IRC在2000初的时候是红极一时的,主要是由于它的便利性和快捷性,但是随着社交网络的发展,博客、论坛等形式的出现,再加上FaceBook、QQ等之后聊天软件的相继涌现,IRC的低私密性、安全性和简陋的界面等局限性相继放大逐渐退出了历史舞台。

3 研究相关工作

在准备实现IRC协议与系统研制之前,我们首先查了相关IRC的概念、理论、应用等实际的相关话题,使得我们对于IRC(Internet Relay Chat)本身有了更加深刻的理解。

之后为了使用Python语言实现对于IRC系统的研制,我们查阅了相关的开源代码。包括但不限于IRC系统机器人的调制,RSA针对聊天内容的加密功能与解密,Python语言多线程功能的实现等等。

4 研究目标、内容和关键问题

4.1 研究目标:

设计IRC客户端,实现基于IRC协议的多人聊天室,并对传输的信息进行加密

4.2 实验原理

服务器与客户端之间通过IRC协议进行通信,在IRC协议中,用户可以加入到频道Channel中,在频道中发送消息,频道中的所有人都能接收到信息。

但大多数情况下,我们需要希望发送的消息是保密的,只有发送端和接收端能够得到消息。因此,需要对消息进行加密,在这里我们使用RSA非对称加密。

RSA非对称加密方法中,存在一对密钥,分别为公钥和私钥。其中公钥公开,私钥秘密保存。在RSA加密通信中,发送端和接收端各有一对密钥,且不相同。发送信息时,发送端用接收端的密钥进行加密,接收端用自身保存的私钥进行解密。由于能够解密的私钥只保存在接收端,因此只有接收端能解开加密内容,如此实现加密。

4.3 实验重点

(1)客户端能够连接到指定的IRC服务器,并能够加入到用户指定的频道Channel,能够向频道中发送消息,并且能够同时接收来自IRC服务器的消息以及其他用户在频道中发送的消息。

(2)通过RSA加密算法对发送消息进行加密,能够实现与相同频道中的指定用户进行加密通信,其他用户无法解密。

(3)设计界面,能够便于用户操作,同时收集用户输入的信息,为用户提供输出信息。

4.4 难点分析

(1)与IRC服务器相连接,需要根据IRC协议配置好发送消息的格式,能够与IRC服务器建立连接。

(2)收发的同步进行,用户发送消息和接收来自服务器的消息是同时进行的过程,应当能够同时进行,保证通信的实时性。

(3)RSA加密算法的实现,需要更新加密密钥,保证每一个客户端生成的一对密钥各不相同,同时需要与加密通信的对象进行连接,互相发送公钥。客户端用接收端的公钥对发送信息进行加密,用自己的私钥对接收信息进行解密。

研究方案和技术路线

(1)在本项目中,我们通过调用irc库中的函数,与IRC服务器建立连接,并且加入到特定的频道中。

(2)设计另一个接收服务器消息的线程,使得用户在操作客户端,例如发送信息的同时,能够接收来自服务器的消息。

(3)利用PyOpenssl库,每一个客户端在开启时自动产生一对独一无二的密钥,保存私钥,公开公钥。利用rsa库,客户端用接收端的公钥对发送信息进行加密,用自己的私钥对接收信息进行解密。

(4)利用PyQt5设计用户界面,并且编写每一个控件的槽函数。

系统设计与实现

6.1 系统总体设计

主要功能和性能

本项目编写的客户端程序,能够提供登录界面,用户可以输入用户名、频道和服务器地址,输入完毕后系统能够自动连接到该服务器的指定频道。

在菜单中,有登录、选择频道、连接到服务器、断开连接、退出的功能,能够方便用户使用。

用户能够在频道中群发消息,也能够通过PRIVCONNECT name与用户名为name的用户进行一对一加密通信。

系统能够实现RSA密钥的生成与更新,保证每一个客户端的一对密钥是独一无二的,私钥只存在用户的电脑上。不同客户端的密钥不相同。发送加密信息时,用接收端的公钥对发送信息进行加密;接收时,用客户端保存的自身私钥对接收信息进行解密。

6.2 关键功能模块实现

在程序一开始,系统利用PyOpenssl库,生成一对密钥,将私钥以变量的形式在程序中保存,不进行任何传输,公钥写入rsa_public_key.pem文件中。

设计一个receive类,建立receive类的一个新的线程,在receive.run()函数中,客户端接收服务器发送的消息,并且进行判断和处理,判断是否为建立私密通信请求,是否为公钥消息,是否为加密消息,以及普通消息。

在客户端(client1)发送建立私密连接请求,即PRIVCONNECT client2时,client1与client2互相发送自身的公钥,存储为rsa_public_key2.pem。在发送加密消息时,调用rsa库中的函数,用对方的公钥即rsa_public_key2.pem,对发送消息进行加密。同时接收加密消息时,用自身的私钥pri_key对接收的加密消息进行解密。

7 部分代码

from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox,QWidget
from PyQt5.QtGui import QTextCursor
import ircchat
import Crypto
import rsa
import socket
import threading
import RSA
import name
import choose
import sys
global server
global channel
global connected
global botnick
global registered
global friend
global private
private=0   #建立私密连接后private=1,否则为0
friend=""   #建立私密连接中,对方的匿名
botnick = "pythonxz"    #自身的匿名即用户名
channel ="#casual"      #频道
server = "open.ircnet.net"       #服务器网站
global rsaUtil
global pri_key
Crypto.key_inital()                 #在文档中新建两个公钥文件,进行初始化
pri_key = Crypto.generate_key()     #产生公钥和私钥
rsaUtil = RSA.RsaUtil(pri_key)      #初始化rsaUtil加密解密类


irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #defines the socket
def send_private():    #在建立私密连接后进行加密发送
    print("sending private\n")
    if connected==1 and registered==1:
        global channel
        global botnick
        print ("sending\n")
        global rsaUtil
        global friend
        ui.label.setText("加密连接到:"+friend+"于频道"+channel)
        message_encode=rsaUtil.encrypt_by_public_key(('<'+botnick+'>' + ui.lineEdit.text()).encode())   #使用对方公钥加密
        print(message_encode)
        irc.send(('PRIVMSG ' + channel + ' :' + "CODED"+str(message_encode.decode())+"\r\n" ).encode())  #发送加密消息
        ui.textEdit.append('<'+botnick+'>' + ui.lineEdit.text() + '\r\n')
        ui.lineEdit.clear()
        ui.textEdit.moveCursor(QTextCursor.End)
    else:
        if connected==0:
            box=QMessageBox()
            box.setWindowTitle("警告")
            box.setText("没有连接到服务器,请点击文件->连接")
            reply=box.exec()
        else:
            box = QMessageBox()
            box.setWindowTitle("警告")
            box.setText("未登录,请点击文件->登录")
            reply = box.exec()
def send_public(): #没有建立私密连接时,不加密发送消息
    if connected==1 and registered==1:
        global private
        if private==0:
            global channel
            global botnick
            print ("sending public\n")
            text=ui.lineEdit.text()
            print(text)
            if text.find("PRIVCONNECT ")!=-1:   #判断是否为建立私密连接的指令
                print("private connecting:\n")
                t5 = text.split("PRIVCONNECT ")  # you can change t and to :)
                to5 = t5[1].strip()  # this code is for getting the first word after !hi
                global friend
                friend=to5
                print("CONNECTING WITH "+friend)
                irc.send(('PRIVMSG ' + channel + ' :' +"PRIVCONNECT "+friend+" "+botnick + "\r\n").encode())
                send_public_key()
            else:   #正常发送公开消息
                print("normal sending\n")
                irc.send(('PRIVMSG ' + channel + ' :' + '<'+botnick+'>' + text + "\r\n").encode())
            ui.textEdit.append('<'+botnick+'>' + text + '\r\n')
            ui.lineEdit.clear()
            ui.textEdit.moveCursor(QTextCursor.End)
        else:
            send_private()
    else:
        if connected==0:
            box=QMessageBox()
            box.setWindowTitle("警告")
            box.setText("没有连接到服务器,请点击文件->连接")
            reply=box.exec()
        else:
            box = QMessageBox()
            box.setWindowTitle("警告")
            box.setText("未登录,请点击文件->登录")
            reply = box.exec()
def send_public_key():  #发送自身公钥
    print("sending public key\n")
    publickfile = open('rsa_public_key.pem', 'r')
    p = publickfile.read()
    print(p)
    p = p.replace("\n","*-----*")
    irc.send(('PRIVMSG ' + channel + ' :'+"PUBLICKEY "+botnick+p+"\r\n").encode())
    publickfile.close()
class recieve (threading.Thread):  #接收类
    def run(self):
        while 1:    #puts it in a loop
            if connected==1:
                global channel
                global friend
                text=irc.recv(2040)  #receive the text
                print ((text).decode())   #print text to console
                if text.find(('PRIVMSG ' + channel + ' :' +"PRIVCONNECT "+botnick+" ").encode())!=-1: #判断是否为私密连接指令
                    t = text.split(('PRIVMSG ' + channel + ' :' +"PRIVCONNECT "+botnick+" ").encode())  # you can change t and to :)
                    to = t[1].strip()  # this code is for getting the first word after !hi
                    friend=to.decode()
                    ui.textEdit.append("connecting with friend:"+friend+"\n")
                    send_public_key() #发送自己的公钥
                if text.find(('PRIVMSG ' + channel + ' :'+"PUBLICKEY "+friend).encode())!=-1:  #判断是否为对方的公钥信息
                    t = text.split(('PRIVMSG ' + channel + ' :' + "PUBLICKEY "+friend).encode())  # you can change t and to :)
                    to = t[1].strip()  # this code is for getting the first word after !hi
                    to_str=to.decode()
                    to_str=to_str.replace("*-----*","\n")
                    print("receive key\n")
                    ui.textEdit.append("receving keys")
                    print(to_str)
                    ui.textEdit.append(to_str)
                    pubfile = open('rsa_public_key2.pem', 'w')  #存储对方的公钥
                    pubfile.write(to_str)
                    pubfile.close()
                    print("write over\n")
                    global rsaUtil
                    global pri_key
                    rsaUtil = RSA.RsaUtil(pri_key)      #利用对方的公钥准备为信息加密
                    print("generate rsa\n")
                    global private
                    private=1
                    ui.textEdit.append("generate rsa\n")
                if text.find(('PRIVMSG ' + channel + ' :'+"CODED").encode()) !=-1: #判断是否为加密信息
                    t = text.split(('PRIVMSG ' + channel + ' :'+"CODED").encode())  # you can change t and to :)
                    to = t[1].strip()  # this code is for getting the first word after !hi
                    print(to)
                    message_decode=rsaUtil.decrypt_by_private_key(to)   #利用自己的私钥解密
                    ui.textEdit.append(str(message_decode.decode())+"\r\n")
                    ui.textEdit.moveCursor(QTextCursor.End)
                else:   #正常接收非加密消息
                    if text != 0:
                        ui.textEdit.append((text).decode())
                        ui.textEdit.moveCursor(QTextCursor.End)
                if text.find(('PING').encode()) != -1:                          #check if 'PING' is found
                    irc.send(("PONG " + str(text.split() [1]) + "\r\n").encode()) #returnes 'PONG' back to the server (prevents pinging out!)
                if text.find((':!hi').encode()) != -1:  # you can change !hi to whatever you want
                    t = text.split((':!hi').encode())  # you can change t and to :)
                    to = t[1].strip()  # this code is for getting the first word after !hi
                    irc.send(('PRIVMSG ' + channel + ' :Hello ' + str(to) + '! \r\n').encode())
thread1 = recieve()
thread1.setDaemon(True)
def irc_connect():      #与IRC服务器建立连接
    if registered==1:
        global channel
        global botnick
        global server
        print("connecting to:" + server)
        ui.textEdit.append("connecting to:" + server)
        irc.connect((server, 6667))  # connects to the server
        global connected
        connected=1
        ui.label.setText("已连接到"+channel+"频道")
        irc.send(("USER " + botnick + " " + botnick + " " + botnick + " :This is a fun bot!\n").encode())  # user authentication
        irc.send(("NICK " + botnick + "\n").encode())  # sets nick
        irc.send("PRIVMSG nickserv :iNOOPE\r\n".encode())  # auth
        irc.send(("JOIN " + channel + "\n").encode())  #join the chan    connected=1
    else:
        box = QMessageBox()
        box.setWindowTitle("警告")
        box.setText("未登录,请点击文件->登录")
        reply = box.exec()
def join_channel(): #显示选择频界面
    Widget2.show()
def register():     #显示登录界面
    Widget.show()
def user_info():    #用户信息收集
    global botnick
    global registered
    global channel
    channel=ui2.lineEdit_3.text()
    botnick=ui2.lineEdit.text()
    registered=1
    global server
    server=ui2.lineEdit_2.text()
    Widget.close()
    MainWindow.show()
    irc_connect()
def choose_channel(): #加入指定频道
    global channel
    channel=ui3.lineEdit.text()
    irc.send(("JOIN " + channel + "\n").encode())  # join the chan    connected=1
    ui.label.setText("已连接到" + channel + "频道")
    Widget2.close()
def disconnect(): #与服务器断开连接
    global connected
    irc.send(("quit" + "\r\n").encode())
    connected=0
def irc_quit(): #退出程序
    MainWindow.close()
    Widget.close()
    Widget2.close()
    exit()
if __name__ == '__main__':
    app = QApplication(sys.argv)
    MainWindow = QMainWindow()
    Widget=QWidget()
    Widget2=QWidget()
    ui = ircchat.Ui_MainWindow()
    ui2=name.Ui_Form()
    ui3=choose.Ui_Form()
    ui.setupUi(MainWindow)
    ui2.setupUi(Widget)
    ui3.setupUi(Widget2)
    Widget.show()
    connected=0
    registered=0
    ui.lineEdit.returnPressed.connect(lambda:send_public())
    ui.action_C.triggered.connect(lambda:irc_connect())
    ui.action_C_2.triggered.connect(lambda:join_channel())
    ui.action_E.triggered.connect(lambda:register())
    ui.action_D.triggered.connect(lambda:disconnect())
    ui.action_Q.triggered.connect(lambda:irc_quit())
    ui2.pushButton.pressed.connect(lambda:user_info())
    ui2.lineEdit_2.setText("open.ircnet.net")
    ui2.lineEdit_3.setText("#casual")
    ui3.pushButton.pressed.connect(lambda:choose_channel())
    thread1.start()
    sys.exit(app.exec_())

完整代码所在地址:(55条消息) 基于Python语言、RSA非对称加密的IRC聊天室客户端源码与应用程序-Python文档类资源-CSDN文库

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

where_are_u

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值