zoukankan      html  css  js  c++  java
  • 简单的远程加解密文件

    
    

    本例通过客户端和服务器端来为大家展示一下AES来远程加解密文件(相关库的使用请自行搜索),通过socket来进行客户端和服务器的通信,客户端对服务器发送过来的密钥字符串、
    iv值和一个字符串(可以为任意值),对客户端相应的文件进行加密操作,在这里大家可以将所有的文件都进行加密操作,请自行测试,但是请大家在测试期间,
    不要使用自己重要的文件来测试,可以创建一些无用的文件来测试。

    各位大牛请绕过,不要喷 ......

    客户端主要是使用服务器上发送过来的key长度进行判断是否为16的整数倍,如果不够则使用随机数来将key填充到AES加解密的要求为止,然后使用getKey将所有生成的随机数进行保存,
    然后再将其加密后,发送到服务器上。加密的密钥是服务器上发送过来的key加上getKey本地生成的随机数字符串,在不知道服务器上保存的数据和密钥及长度,大大增加了解密的难度。

    具体的客户端代码如下:

    """
    write by HuSoul
    """
    # 客户端代码
    # -*-  coding:utf-8  -*-
    
    import random
    from Crypto.Cipher import AES
    import socket
    
    # 使用AES加密文件的函数
    def AESEncrypt_File(fs,key=b'123456789!@#$%^&',iv='3333333333333333',keyList='123456789!@#$%^&*(ABCDEFGHI'):
    
        keyLength = len(key)
        getKey = ''   # 保存在本地生成的所有随机数
        key_b = key   # 加密随机数的密钥
    
        if keyLength not in [16,24,32]:
            if keyLength < 16:
                key_b = key_b + keyList[6:16 - keyLength + 6]   # 至于这个密钥的选择可以自己定义一个空间,保证该密钥是16的整数倍
                for i in range(16 - keyLength):
                    r = chr(random.randint(33,126))   # 生成随机数 33-126的可见字符
                    key += r    # 将发送过来不够长度的密钥,加上随机字符到合法的密钥
                    getKey += r
            elif 16 < keyLength < 24:
                key_b = key_b + keyList[9:24 - keyLength + 9]
                for i in range(24 - keyLength):
                    r = chr(random.randint(33,126))
                    key += r
                    getKey += r
            elif 24 < keyLength < 32:
                key_b = key_b + keyList[11:32 - keyLength + 11]
                for i in range(32 - keyLength):
                    r = chr(random.randint(33,126))
                    key += r
                    getKey += r
            else:
                key = key[0:32]
    
        cipherFile = AES.new(key,AES.MODE_CBC,iv)   # 生成加密时使用的实际密码
        enKey = AES.new(key_b,AES.MODE_CBC,iv)
    
        x = len(fs) % 16    # 因为AES分块大小固定为16字节,所以要判断输入的文本是否为16字节的整数倍
    
        fs_pad = ''
        if x != 0:
            fs_pad = fs + '0' * (16 - x)   # 当不是16字节的整数倍,就使用 '0' 字符补足
            print('fs_pad is :' + fs_pad)
            print(len(fs_pad))
            print(len(fs_pad) % 16)
    
        msg = cipherFile.encrypt(fs_pad)   # 加密文件流
        if len(getKey.strip()) < 16:
            getKey += '*' * (16 - len(getKey))
        remainingKey = enKey.encrypt(getKey)   # 加密剩下的key
        return msg,remainingKey
    
    # 使用AES解密文件的函数
    def AESDecrypt_File(fs,key=b'123456789!@#$%^&',iv='3333333333333333'):
    
        # AES key must be either 16, 24, or 32 bytes long
        cipher = AES.new(key,AES.MODE_CBC,iv)
    
        x = len(fs) % 16    # 因为AES分块大小固定为16字节,所以要判断输入的文本是否为16字节的整数倍
    
        fs_pad = fs
        if x != 0:
            fs_pad += '0' * (16 - x)   # 当不是16字节的整数倍,就使用 '0' 字符补足
            print('fs_pad is :' + fs_pad)
            print(len(fs_pad))
            print(len(fs_pad) % 16)
    
        msg_pd = cipher.decrypt(fs_pad)
        return msg_pd
    
    
    def EncryptFile(fs,key=b'123456789!@#$%^&',iv='3333333333333333',keyList=''):
    
        getFile = open(fs,'rb')
        getFile.seek(0,0)
        fs_msg = getFile.read()
        getFile.close()
    
    
        # encrypt src FileStream
        fsCon = fs.split('.')
        fen = open(fsCon[0]+'_b.'+ fsCon[1],'wb')
        fen_msg,getKey = AESEncrypt_File(fs_msg,key,iv,keyList)
        fen.writelines(fen_msg)
        fen.close()
    
        return getKey
    
    
    def DecryptFile(fs,key=b'123456789!@#$%^&',iv='3333333333333333'):
        getFile = open(fs,'rb')
        getFile.seek(0,0)
        fs_msg = getFile.read()
        getFile.close()
    
        # decrypt src FileStream
        fsCon = fs.split('.')
        fde = open(fsCon[0] + 'b.' + fsCon[1],'wb')
        fde_msg = AESDecrypt_File(fs_msg,key,iv)
        fde.writelines(fde_msg)
        fde.close()
    
    # 与服务器通信
    def Connection():
        """
        Connecting by Client
        :return:
        """
        ID = 12345678
        Host = '127.0.0.1'
        Port = 7896
        # 先获取相应的密钥信息
        s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        s.bind((Host,Port))
        s.listen(5)
        q = True
        getKey = ''
        while True:
            conn,addr = s.accept()
            while q:
                # 接收相应的密钥 iv string
                receive = conn.recv(1024)
                info = receive.split(':')
                if info[0] == 'en':
                    # Encrypt test
                    getKey = EncryptFile('Desert.jpg',info[1],info[2],info[3])
                    conn.close()
                    print('file is already encrypt successfully')
                    q = False
    
                    # 再发送剩余的密钥给服务器
                    c2s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
                    c2s.connect((Host,9999))
                    c2s.sendall(str(ID) + '0x255' + getKey)
                    c2s.close()
                elif info[0] == 'de':
                    # Decrypt test
                    DecryptFile('Desert_b.jpg',info[1],info[2])
                    conn.close()
                    print('file is already decrypt successfully')
                    # 发送信息给服务器
                    c2s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
                    c2s.connect((Host,9999))
                    c2s.sendall('de:Decrypt Successfully ...')
                    c2s.close()
                    q = False
    if __name__ == '__main__':
      Connection()
    在服务器端则只需使用socket进行对客户端进行连接(对于socket的使用请自行搜索),设置相关的参数和值,发送相应的数据和命令来达到加解密远程文件的操作。
    # 服务器端的代码
    
    #   -*- coding:utf-8   -*-
    import socket
    from Crypto.Cipher import AES
    
    Host = '127.0.0.1'
    Port = 9999
    
    # key
    key = 'testtest'
    # iv
    iv = '1234567890QWERTY'   # iv是要求要16位、24位和32位的,与加密的密钥长度一样,这个值可以自己修改
    # keyList
    keyList = '1$d9Ry*g2^Sj0&b%3)+6}vP4@,Wv-+A)'  # 用于加密随机数时,填充到密钥的后面的字符集
    
    keyLength = len(key)
    
    # 加密代码
    s2cEn = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s2cEn.connect((Host,7896))
    s2cEn.sendall('en'+ ':' + key + ':' + iv + ':' + keyList)
    
    # 获取远程主机发送过来的加密随机数字符串
    ss = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    ss.bind((Host,Port))
    ss.listen(5)
    q = True
    getKey = ''
    while True:
        conn,addr = ss.accept()
        while q:
            remainingKey = conn.recv(1024)
    
            conn.close()
            print('Successful to get the person key by : ' + str(addr))
            q = False
            if keyLength not in [16,24,32]:
                if keyLength < 16:
                    key_b = key + keyList[6:16 - keyLength + 6]
                elif 16 < keyLength < 24:
                    key_b = key + keyList[9:24 - keyLength + 9]
                elif 24 < keyLength < 32:
                    key_b = key + keyList[11:32 - keyLength + 11]
                else:
                    key = key[0:32]
            # decrypt received remainingKey
            remainKey = remainingKey.split('0x255')
            print('remainKey[1] : ' + remainKey[1])
            decryptRekey = AES.new(key_b,AES.MODE_CBC,iv)
            getKey = decryptRekey.decrypt(remainKey[1])
            print(getKey)   # 获取随机数
            
    
    # 解密代码
    getKey = '12345678'  # 随机数字符串,从上述的加密代码中控制台输出的getKey值
    deKey = key + getKey
    s2cDe = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s2cDe.connect((Host,7896))
    s2cDe.sendall('de' + ':' + deKey + ':' + iv)
    当你要解密远程文件时,调用解密代码进行解密文件,但是此时应当将上述加密的代码注释,当然你可以用一个选项来选择相应的操作,
    对远程主机进行操作,可以修改适当的代码来达到你的需求。

    至于上述的过程虽然没有将所有的代码都解释的很清楚,但是我相信代码上的注释大家还是可以看懂的。虽然这段代码的意义不大,在一些加密文件的手段上也是用代码堆积而成的,
    但是我希望可以给大家编写程序时带来灵感,通过不同的案例来启发大家对编程的热爱。

    免责声明: 
      请勿用于非法用途,如有盗用,后果自负,一切责任与本人无关
     作者:http://www.cnblogs.com/GHost-Ma/
     出处:http://www.cnblogs.com/GHost-Ma/
     版权:本文版权归作者和博客园共有
     转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
    http://www.cnblogs.com/GHost-Ma/
  • 相关阅读:
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    C#使用BouncyCastle操作国密SM3
    Win10 2004种子
    Excel对比两列数据,找到重复项
    CentOS7 + frp远程访问内网Windows电脑
    Docker on Mac OS
    MySQL5.6中查询多边形包含点情况(ST_Contains、ST_Within)
    SQL查询表的所有字段名
    清除文本中Html的标签
  • 原文地址:https://www.cnblogs.com/GHost-Ma/p/5365371.html
Copyright © 2011-2022 走看看