AES文件加密项目分析(2)

参考项目:pyaes

之前仿照Github上的项目Python-File-Encryptor,分别在两台计算机上建立了加密端和解密端,加密端将用来充当实验品的文件加密,解密端负责远程拷贝加密后的文件再解密文件。

加密端代码:

from Crypto import Random
from Crypto.Cipher import AES
import os
import os.path

Key = b'\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4'


def pad(s):
    return s + b"\0" * (AES.block_size - len(s) % AES.block_size)

def encrypt(message, key):
    message = pad(message)
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return iv + cipher.encrypt(message)

def Encryption(file):
    with open(r'E:\EncryptionTest\FileEncryption' + '\\' + file, 'rb') as fo:
        plaintext = fo.read()
    enc = encrypt(plaintext, Key)
    with open(r'E:\EncryptionTest\NewFile' + '\\'+ file, 'wb') as fo:
        fo.write(enc)
    os.remove(r'E:\EncryptionTest\FileEncryption'+ '\\'+ file)


# 打开文件夹并统计文件个数
path = r'E:\EncryptionTest\FileEncryption'      # 输入文件夹地址
files = os.listdir(path)   # 读入文件夹
for file in files:
    Encryption(file)

解密端解密:

#!/usr/bin/env python3
import os
import paramiko
import unicodedata
import sys
from scp import SCPClient

from Crypto import Random
from Crypto.Cipher import AES
import os.path
from os import listdir
from os.path import isfile, join
import time

Key = b'\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4'

def decrypt(ciphertext, key):
	iv = ciphertext[:AES.block_size]
	cipher = AES.new(key, AES.MODE_CBC, iv)
	plaintext = cipher.decrypt(ciphertext[AES.block_size:])
	return plaintext.rstrip(b"\0")

def decrypt_file(file_name):
	with open(file_name, 'rb') as fo:
		ciphertext = fo.read()
	os.remove(file_name)
	dec = decrypt(ciphertext, Key)
	with open(file_name, 'wb') as fo:
		fo.write(dec)

destination = sys.argv[1]	# 目的文件路径
print('\n'+destination+'\n')
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(address, 22, username, password)
scp = SCPClient(client.get_transport())
scp.get(os.path.join('E:/EncryptionTest/NewFile'), destination, recursive=True)
time.sleep(1200)
scp.close()
client.close()

path = destination + '/' + 'NewFile'
files = os.listdir(path)
for file in files:
	decrypt_file(path+'/'+file)

然而,在实验中一些文件出现了损坏。打不开了。

接下来分析Github项目pyaes:

这其实是一个算法库,不是一个单独的应用程序,要用到里面的东西可以调用,先看看作者给的README文件:

AES常见的操作模式包括CBC, CFB, CTR, ECB和OFB
通常推荐CBC和CTR模式,ECB模式不推荐

当然,这几种模式都需要密钥和初始化向量,比如这样:

import pyaes

# A 256 bit (32 byte) key
key = "This_key_for_demo_purposes_only!"

# For some modes of operation we need a random initialization vector
# of 16 bytes
iv = "InitializationVe"

由于大多数操作模式需要特定块大小或段大小的块中的数据,因此在处理大型任意数据流或数据字符串时可能会很困难。为此,函数库提供了BlockFeeder,具体的操作方法如下:

import pyaes

# Any mode of operation can be used; for this example CBC
key = "This_key_for_demo_purposes_only!"
iv = "InitializationVe"

ciphertext = ''

# We can encrypt one line at a time, regardles of length
encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(key, iv))
for line in file('/etc/passwd'):
    ciphertext += encrypter.feed(line)

# Make a final call to flush any remaining bytes and add paddin
ciphertext += encrypter.feed()

# We can decrypt the cipher text in chunks (here we split it in half)
decrypter = pyaes.Decrypter(pyaes.AESModeOfOperationCBC(key, iv))
decrypted = decrypter.feed(ciphertext[:len(ciphertext) / 2])
decrypted += decrypter.feed(ciphertext[len(ciphertext) / 2:])

# Again, make a final call to flush any remaining bytes and strip padding
decrypted += decrypter.feed()

print file('/etc/passwd').read() == decrypted

在上述这段代码中,属于加密部分的是:

# We can encrypt one line at a time, regardles of length
encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(key, iv))
for line in file('/etc/passwd'):
    ciphertext += encrypter.feed(line)

# Make a final call to flush any remaining bytes and add paddin
ciphertext += encrypter.feed()

属于解密部分的是:

# We can decrypt the cipher text in chunks (here we split it in half)
decrypter = pyaes.Decrypter(pyaes.AESModeOfOperationCBC(key, iv))
decrypted = decrypter.feed(ciphertext[:len(ciphertext) / 2])
decrypted += decrypter.feed(ciphertext[len(ciphertext) / 2:])

# Again, make a final call to flush any remaining bytes and strip padding
decrypted += decrypter.feed()

关于Blockfeeder中的Encrypter类和Decrypter类,抽出源码部分:

class BlockFeeder(object):
    '''The super-class for objects to handle chunking a stream of bytes
       into the appropriate block size for the underlying mode of operation
       and applying (or stripping) padding, as necessary.'''

    def __init__(self, mode, feed, final, padding = PADDING_DEFAULT):
        self._mode = mode
        self._feed = feed
        self._final = final
        self._buffer = to_bufferable("")
        self._padding = padding

    def feed(self, data = None):
        '''Provide bytes to encrypt (or decrypt), returning any bytes
           possible from this or any previous calls to feed.

           Call with None or an empty string to flush the mode of
           operation and return any final bytes; no further calls to
           feed may be made.'''

        if self._buffer is None:
            raise ValueError('already finished feeder')

        # Finalize; process the spare bytes we were keeping
        if data is None:
            result = self._final(self._buffer, self._padding)
            self._buffer = None
            return result

        self._buffer += to_bufferable(data)

        # We keep 16 bytes around so we can determine padding
        result = to_bufferable('')
        while len(self._buffer) > 16:
            can_consume = self._mode._can_consume(len(self._buffer) - 16)
            if can_consume == 0: break
            result += self._feed(self._buffer[:can_consume])
            self._buffer = self._buffer[can_consume:]

        return result


class Encrypter(BlockFeeder):
    'Accepts bytes of plaintext and returns encrypted ciphertext.'

    def __init__(self, mode, padding = PADDING_DEFAULT):
        BlockFeeder.__init__(self, mode, mode.encrypt, mode._final_encrypt, padding)


class Decrypter(BlockFeeder):
    'Accepts bytes of ciphertext and returns decrypted plaintext.'

    def __init__(self, mode, padding = PADDING_DEFAULT):
        BlockFeeder.__init__(self, mode, mode.decrypt, mode._final_decrypt, padding)

列举一下其中调用的其他的函数和变量:
(1)

PADDING_DEFAULT    = 'default'

(2)

def to_bufferable(binary):
	if isinstance(binary, bytes):
		return binary
	return bytes(ord(b) for b in binary)

def to_bufferable(binary):
	return binary

(3)

def _block_can_consume(self, size):
	if size >= 16: return 16
	return 0

def _stream_can_consume(self, size):
	return size

def _segment_can_consume(self, size):
	return self.segment_bytes * int(size // self.segment_bytes)

AESSegmentModeOfOperation._can_consume = _segment_can_consume
AESStreamModeOfOperation._can_consume = _stream_can_consume
AESBlockModeOfOperation._can_consume = _block_can_consume
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值