soapgu / PlayPen

学习笔记

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

简单位运算加解密实现

soapgu opened this issue · comments

  • 按位取反加密

这是一个最简单的加解密方式,直接再执行相同操作就可以恢复原文,非常简单。

代码里面是执行~操作符即可。我们看一下代码原理

byte_value = b'a'  # 这是一个ASCII码对应'a'字符的字节对象

print(byte_value[0])
# 提取第一个(也是唯一一个)字节,并进行按位取反
inv_byte = ~byte_value[0]
print(inv_byte)

执行结果为97和-98

学过ASCII编码的都知道,97就是a的编码,但是求反后-98是什么鬼,其实这是用补码的形式来表示

我们用二进制来表达下再看看

97 : 0110 0001
-98 : 1001 1110

是不是有感觉了。问题是我如果要操作文件内容的加密,就必须转为无符号整型,就是8位二进制。所以转为0~255范围数据。

代码如下

byte_value = b'a'  # 这是一个ASCII码对应'a'字符的字节对象

def bitwise_not_encrypt( input : int ):
    print(f"input byte:{input}")
    output = ~input & 0xFF
    # Python内部自动处理了符号扩展,因此得到的结果仍是在0-255之间的数字
    # 由于Python内建的int类型是足够大的,它能存储任何这样的小整数而无需担心溢出问题
    print(f"output byte:{output}")
    return output

# 提取第一个(也是唯一一个)字节,并进行按位取反
print("encrypt>>>>>>>")
encrypt = bitwise_not_encrypt(byte_value[0])
print("decrypt>>>>>>>")
decrypt = bitwise_not_encrypt(encrypt)

文件操作相关代码

from Crypto.Random import get_random_bytes
import binascii
import os
import argparse
import time


parser = argparse.ArgumentParser(description='Process some files.')
parser.add_argument('-f', '--input-file', required=True, help='The input file')

args = parser.parse_args()

print(f"Input file: {args.input_file}")

ENCRYPT_SIZE = 1024
BLOCK_SIZE = 16 * 1024
download_path = args.input_file
output_filename = f"encrypt_{args.input_file}"

#print(f"key lenght:{len(binascii.unhexlify(keys))}")

in_file_length = os.path.getsize(download_path)
block_count = in_file_length / BLOCK_SIZE
print(in_file_length)
start_time = time.time()
count = 0
with open(download_path, 'rb') as in_file:
    with open(output_filename, 'wb') as out_file:
        # 1. write mess 1k data first
        out_file.write( get_random_bytes(1024) )
        # 2. read 1k data
        head = in_file.read(ENCRYPT_SIZE)
        # 3. aes encrypt and write
        #hex_string = binascii.hexlify(head).decode()
        #print(f"head content:{hex_string}")
        crypted_chunk = bytes([~byte & 0xFF for byte in head])
        out_file.write(crypted_chunk)
        # 4. copy other part file
        head_time = time.time() - start_time
        print(f"加密头时间: {head_time} 秒")
        while content := in_file.read(BLOCK_SIZE):
            out_file.write(content)

out_file_length = os.path.getsize(output_filename)
print(f"encrypt ok,size {out_file_length}")
end_time = time.time()
run_time = end_time - start_time
print(f"按位取反加密运行时间: {run_time} 秒")

解密过程是完全对称的,这里就略过

其中有个计算机概念非常重要就是补码,还是有必要好好了解一下的

0 ^ 0 = 0
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
  • 异或的特性

异或运算法则具有自反性、交换性和互补性

A ^ 0 = A
A ^ A = 0
(A ^ B) ^ C = A ^ (B ^ C) 
 (B ^ A) ^ A = B ^ 0 = B  
  • 加解密算法
from itertools import cycle

def xor_cipher(text, key):
    encrypted_text = bytes([(c^k) for c, k in zip(text, cycle(key))])
    return encrypted_text

def xor_decipher(encrypted_text, key):
    # 加密和解密使用的是同一函数,因为异或运算具有相反可逆性
    return xor_cipher(encrypted_text, key)

plaintext = b"Hello, World!"

key = b'shgbit'


encrypted = xor_cipher(plaintext, key)
print("Encrypted Text:", encrypted)
decrypted = xor_decipher(encrypted, key)
print("Decrypted Text:", decrypted)
  • 文件替换方式加解密

对于大文件的加解密,文件的复制是一个很大的负担,如果我们只是部分加密可以使用快速替换的方式

但是需要满足下面条件

  • 加密前后文件大小不变
  • 对称加解密

同时文件还有一个模式读写模式来实现操作

from itertools import cycle
import os
import argparse
import time

def xor_cipher(text, key):
    #encrypted_text = ''.join(chr(ord(c) ^ ord(k)) for c, k in zip(text, cycle(key)))
    encrypted_text = bytes([(c^k) for c, k in zip(text, cycle(key))])
    return encrypted_text


parser = argparse.ArgumentParser(description='Process some files.')
parser.add_argument('-f', '--input-file', required=True, help='The input file')

args = parser.parse_args()

print(f"Input file: {args.input_file}")

ENCRYPT_SIZE = 1024
download_path = args.input_file

#print(f"key lenght:{len(binascii.unhexlify(keys))}")

in_file_length = os.path.getsize(download_path)
print(in_file_length)
start_time = time.time()
count = 0
with open(download_path, 'rb') as in_file:
    # read 1k data
    head = in_file.read(ENCRYPT_SIZE)
    # aes encrypt and write
    crypted_chunk = xor_cipher(head,b"shgbit")
    

with open(download_path, 'r+b') as out_file:
    out_file.seek(0)
    out_file.write(crypted_chunk)    

end_time = time.time()
run_time = end_time - start_time
print(f"按位异或加(解)密运行时间: {run_time} 秒")

看运行结果

guhui@guhuideMacBook-Pro RsaDemo % python3 xor_quick_encrypt.py -f film.mkv  
Input file: film.mkv
16342579412
按位异或加(解)密运行时间: 0.00012111663818359375 秒
guhui@guhuideMacBook-Pro RsaDemo % python3 xor_quick_encrypt.py -f film.mkv
Input file: film.mkv
16342579412
按位异或加(解)密运行时间: 0.00012183189392089844 秒

16G的电影文件也是秒编秒解

相关文件模式参考