- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Python 实现RSA加解密文本文件由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
近来在使用python写项目,特此记录一下项目中遇到的文件加解密问题。 关于python版本的加密算法,随便搜一搜还是可以检索出来很多的,不过大都是同一篇文章在不同的平台来回发布,或者就是转载,而且例举的都是最简单的情况,那么,实际项目中使用的话,肯定会比这个要稍微复杂一些,比如我的需求就是要加密一个使用mysqldump出来的数据库脚本文件,直接拿网上的例子过来调用肯定是不行的,所以不得不自己研究了一番,特此记录.
项目选型的算法是RSA非对称加密算法,关于这个算法不做过多的解释,咱们划重点:
因为我们使用的是PKCS1Padding占用了11个byte,那么它能加密的明文长度就必须减去这11个byte 。
基于以上三点,我们大概可以知道要完成文件加解密,我们可能会遇到什么问题?
一次性加密明文的长度是和密钥长度有关系的,那么我们要加密一个文件,不能一次性将文本内容读取出来,然后加密 如果文件很大,我们也不可能将文件内容一次性读取到内存当中,可能会直接导致服务器无法响应其他请求,这肯定是不合理的 文本被加密之后,回头解密,如果读取的长度有差异势必导致解密失败,那么这个数据库备份文件就废了,这个就比较危险了 。
安装依赖,python版本3.7.4 。
1
|
pip
install
pycryptodomex -i https:
//pypi
.tuna.tsinghua.edu.cn
/simple/
|
导入模块:
1
2
3
4
5
|
import
base64
from
Cryptodome
import
Random
from
Cryptodome.PublicKey
import
RSA
from
Cryptodome.Cipher
import
PKCS1_v1_5 as Cipher_pkcs1_v1_5
from
Cryptodome.Signature
import
PKCS1_v1_5 as Signature_pkcs1_v1_5
|
生成公钥+私钥,注意这里我们生成的公钥长度是1024bit 。
1
2
3
4
5
6
7
8
9
10
11
|
# 伪随机数生成器
random_generator
=
Random.new().read
# rsa算法生成实例
rsa
=
RSA.generate(
1024
, random_generator)
private_pem
=
str
(rsa.exportKey(), encoding
=
"utf-8"
)
with
open
(
"client-private.pem"
,
"w"
) as f:
f.write(private_pem)
public_pem
=
str
(rsa.publickey().exportKey(), encoding
=
"utf-8"
)
with
open
(
"client-public.pem"
,
"w"
) as f:
f.write(public_pem)'''
|
加密,这里对传入的明文长度做了切分,因为我们生成的密钥长度为1024bit,所以我们一次加密的明文长度不能超过117个byte 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
def
rsa_encrypt(plaintext, pub_key):
'''
rsa 加密
:param plaintext: 明文
:param pub_key:公钥
'''
message
=
plaintext.encode(
"utf-8"
)
length
=
len
(message)
default_length
=
117
# 1024/8 - 11 1024为密钥长度
rsakey
=
RSA.importKey(pub_key)
cipher
=
Cipher_pkcs1_v1_5.new(rsakey)
# 不需要切分
if
length <
=
default_length:
return
default_rsa_encrypt(cipher, message)
# 需要切分
offset
=
0
result
=
[]
while
length
-
offset >
0
:
if
length
-
offset > default_length:
result.append(default_rsa_encrypt(
cipher, message[offset:offset
+
default_length]))
else
:
result.append(default_rsa_encrypt(cipher, message[offset:]))
offset
+
=
default_length
return
"\n"
.join(result)
def
default_rsa_encrypt(cipher, message):
ciphertext
=
base64.b64encode(cipher.encrypt(message))
# print(b"ciphertext:"+ciphertext)
ciphertext_decode
=
ciphertext.decode(
"utf-8"
)
# print("ciphertext_decode:"+ciphertext_decode)
return
ciphertext_decode
|
解密 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
def
rsa_decrypt(ciphertext, priv_key):
'''
rsa 解密
:param ciphertext:密文
:param priv_key:私钥
'''
message
=
base64.b64decode(ciphertext)
length
=
len
(message)
default_length
=
128
rsakey
=
RSA.importKey(priv_key)
cipher
=
Cipher_pkcs1_v1_5.new(rsakey)
if
length <
=
default_length:
return
default_rsa_decrypt(cipher, message)
# 需要分段
offset
=
0
result
=
[]
while
length
-
offset >
0
:
if
length
-
offset > default_length:
result.append(rsa_decrypt(
cipher, message[offset:offset
+
default_length]))
else
:
result.append(rsa_decrypt(cipher, message[offset:]))
offset
+
=
default_length
decode_message
=
[x.decode(
"utf-8"
)
for
x
in
result]
return
"".join(decode_message)
def
default_rsa_decrypt(cipher, message):
plaintext
=
cipher.decrypt(message, random_generator)
# print(b"plaintext:"+plaintext)
plaintext_decode
=
plaintext.decode(
"utf-8"
)
# print("plaintext_decode:"+plaintext_decode)
return
plaintext_decode
|
加解密文件,考虑开头我们提出的问题,采用了逐行读取,逐行加密,加密后密文也逐行写入 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
def
rsa_encrypt_file(file_path, save_path, pub_key):
'''
rsa 加密文件
:param file_path:需要加密文件路径
:param save_path:加密之后存放的文件路径
:param pub_key:公钥
'''
with
open
(file_path,
"r"
, encoding
=
"utf-8"
) as f:
line
=
f.readline()
# 读取一行
while
line:
context
=
rsa_encrypt(line, pub_key)
# 加密切割后的字符
with
open
(save_path,
"a"
, encoding
=
"utf-8"
) as w:
w.write(context
+
"\n"
)
line
=
f.readline()
def
rsa_decrypt_file(file_path,save_path,priv_key):
'''
rsa 解密文件
:file_path:需要解密的文件路径
:save_path:解密之后存放的文件路径
:priv_key:私钥
'''
with
open
(file_path,
"r"
,encoding
=
"utf-8"
) as f:
line
=
f.readline()
while
line:
context
=
rsa_decrypt(line.strip(
"\n"
),priv_key)
with
open
(save_path,
"a"
,encoding
=
"utf-8"
) as w:
w.write(context)
line
=
f.readline()
|
测试,一开始我使用的是自己随便输入的一行很长的数字文本,亲测没有问题,但是当我直接使用我的数据库脚本文件的时候,加密可以成功,但是会遇到解密后解码失败的情况,当时百思不得其解,我以为是字符集的问题,于是我将utf-8,换成了gb2312,加解密成功了,当时心花怒放,直到我重新加解密了另一个备份文件,又遇到解码失败,当时就睡不着觉了~ 。
直到我看到了这句话不完整的多字节序列(incomplete multibyte sequence)我瞬间明白了,因为我的脚本文件中含有中文,utf8 编码一个汉字是3个byte,gb2312编码一个汉字是2个byte,只要是多字节,那么做切割的时候,就有可能一个汉字被切割成了两部分,那么自然会导致无法解码成正确的汉字了,问题已经明了,就看怎么解决了.
因为是脚本文件,处理不好就有可能导致脚本执行失败,最终导致数据库还原失败,这就违背项目初衷了~ 。
所以我想了一个办法,先对每一行文本做字符编码判断,超过了117,最后一个字符就不累计上去,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
def
cut_string(message,length
=
117
):
result
=
[]
temp_char
=
[]
for
msg
in
message:
#遍历每一个字符
msg_encode
=
msg.encode(
"utf-8"
)
#对每一个字符编码
temp_encode
=
"
".join(temp_char).encode("
utf
-
8
")
#累计编码之后的字节数
if
len
(temp_encode)
+
len
(msg_encode) <
=
length:
#如果小于约定的长度,加添加入结果集
temp_char.append(msg)
else
:
#如果已经超过了约定的长度,就添加入下一个结果集
result.append("".join(temp_char))
temp_char.clear()
temp_char.append(msg)
result.append("".join(temp_char))
return
result
|
加密方法需要重新调整一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
def
rsa_encrypt_file(file_path,save_path,pub_key):
'''
rsa 加密文件
:param file_path:需要加密文件路径
:param save_path:加密之后存放的文件路径
:param pub_key:公钥
'''
with
open
(file_path,
"r"
,encoding
=
"utf-8"
) as f:
line
=
f.readline()
#读取一行
while
line:
cut_lines
=
cut_string(line)
# 切割字符 保证汉字不被切割
for
cut_line
in
cut_lines:
context
=
rsa_encrypt(cut_line,pub_key)
#加密切割后的字符
with
open
(save_path,
"a"
,encoding
=
"utf-8"
) as w:
w.write(context
+
"\n"
)
line
=
f.readline()
|
到此问题就已经解决了,其实有了这个cut_string方法之后,之前写的加解密方法中不需要再做切分,但是代码保留.
上面的方法,加解密的效率非常的低,因为是逐行加解密,一个300M的脚本文件,加密完成耗时40分钟,这个实在是太难受了,所以调整了策略,先压缩再加密,所以就涉及到二进制文件的读取与写入,最后的实现代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
def
rsa_encrypt_binfile(file_path,save_path,pub_key):
'''
rsa 加密二进制文件
:param file_path:需要加密文件路径
:param save_path:加密之后存放的文件路径
:param pub_key:公钥
'''
with
open
(file_path,
'rb'
) as f:
message
=
f.read()
length
=
len
(message)
default_length
=
117
# 1024/8 - 11 1024为密钥长度
rsakey
=
RSA.importKey(pub_key)
cipher
=
Cipher_pkcs1_v1_5.new(rsakey)
# 不需要切分
result
=
[]
if
length <
=
default_length:
result.append(base64.b64encode(cipher.encrypt(message)))
# 需要切分
offset
=
0
while
length
-
offset >
0
:
if
length
-
offset > default_length:
result.append(base64.b64encode(cipher.encrypt(message[offset:offset
+
default_length])))
else
:
result.append(base64.b64encode(cipher.encrypt(message[offset:])))
offset
+
=
default_length
with
open
(save_path,
"ab+"
) as w:
for
ciphertext
in
result:
ciphertext
+
=
b
"\n"
w.write(ciphertext)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
def
rsa_decrypt_binfile(file_path,save_path,priv_key):
'''
rsa 解密二进制文件
:file_path:需要解密的文件路径
:save_path:解密之后存放的文件路径
:priv_key:私钥
'''
with
open
(file_path,
"rb"
) as f:
line
=
f.readline()
while
line:
message
=
base64.b64decode(line.strip(b
"\n"
))
rsakey
=
RSA.importKey(priv_key)
cipher
=
Cipher_pkcs1_v1_5.new(rsakey)
plaintext
=
cipher.decrypt(message, random_generator)
with
open
(save_path,
'ab+'
) as w:
#追加写入
w.write(plaintext)
line
=
f.readline()
|
以上就是Python 实现RSA加解密文本文件的详细内容,更多关于python rsa加解密的资料请关注我其它相关文章! 。
原文链接:https://www.cnblogs.com/dwBurning/p/python_rsa.html 。
最后此篇关于Python 实现RSA加解密文本文件的文章就讲到这里了,如果你想了解更多关于Python 实现RSA加解密文本文件的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我有一个 C# 应用程序调用 Java 网络服务来验证用户密码。我想让 C# 应用程序加密密码,然后让 Java Web 服务解密密码。我已经完成了 Java 端的代码(解密代码),但我无法找出 C#
我正在使用以下代码在使用 openssl 的 Windows 中使用 C 加密和解密二进制数据。如您所见,在这两个函数中,我都知道纯文本的大小。有什么方法可以在不知道纯文本大小的情况下解密消息? #i
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我有一个非常恼人的问题,Java中使用RSA算法对字符串进行不可靠的加密和解密。它似乎只能在大约 35% 的时间内工作,而且我不明白为什么它有时能工作,有时却不能。这是我写的一些测试代码,试图验证加密
我已经设法编写了用于文件加密/解密的函数。但它非常慢,尤其是随着文件大小的增加。例如几MB长的音频/视频文件 我几乎浏览了所有帖子来改进它,并尝试更改算法。如果有任何更改可以帮助我提高性能,请帮助我。
我正在尝试让我的转置密码发挥作用。 每当我将加密方法得到的密文输入解密方法时,我应该得到原始的明文......但事实并非如此...... 我做错了什么? 感谢您的帮助! public String E
我正在使用密码来加密和解密消息: public String encrypt(String string) throws InvalidKeyException, IllegalBlockSizeEx
我有一个在 MySQL 中存储数据的 spring-mvc 堆栈。其中一些数据需要保护,所以我想我应该加密它。由于我以后可能需要使用这些数据(信用卡、SSN 等),所以我需要对其进行解密。我认为这排除
作为一名SEOER,都想了解百度算法,通过算法原理来找到捷径的优化方案,那么今天我把研究多年的百度算法原理解密给大家,可能不是最好的,但是我可以给大家保证,这些都是非常实际的。希望给SEOER带来一
我试图找到一种技术来加密和解密程序中的文件,而无需将密码硬编码到程序中,也无需向用户询问密码。 如果我也可以从我正在编写的另一个程序中解密文件,那就太好了。 到目前为止,我还没有多少运气找到一种看起来
有没有一种方法可以使用作为字符串参数传递给程序的私钥而不是使用存储在机器上的证书来解密 PowerShell 中的 RSA?欢迎任何帮助,我的代码如下。 Function Decrypt-Asymme
通过问题Is it possible to use the Grails Jasypt plugin outside the GORM layer for simple String encrypti
我需要解密/加密我的域类中的几列,并且正在寻找有关如何做的信息。我已经找到了jasypt加密插件,但不幸的是它似乎与Grails 2.4不兼容。 我可能可以将一些东西拼凑在一起,但是想要确保Im遵循最
我需要有关声音文件加密/解密的帮助。我想在存储这个声音文件时加密一个声音文件,并在播放这个文件时解密它。我阅读了有关 java 中的加密/解密以及 java 中可用于此的大量示例代码。但这些程序不适用
我很感兴趣是否可以使用 Excel Visual Basic 和某些加密服务提供程序进行字符串加密/解密。 我找到了一个演练 Encrypting and Decrypting Strings in
我们正在使用加密/解密和UIIMAGE。如果我们在不保存到iphone画廊的情况下进行加密和解密以及UIIMAge,则可以正常工作,但是,如果我们进行加密,保存到画廊,将(加密的图像)加载到应用程序中
我正在做一个像这样的简单程序: package rsaexample; import java.io.*; import java.math.BigInteger; import java.secur
我发现这段代码返回给定字符串的校验和。 public static String getChecksum(String md5) { int counter = 0; while (c
我在 Java SE 和 Android 项目上使用相同的代码。在 Java 和 Android 中运行的应用程序连接到相同的 MQTT 代理并交换消息。消息使用 AES 进行加密/解密。我对 Jav
我想在 openssl/libcrypto 中使用 RSA 加密/解密一个长文件(我知道 AES 更好,但这只是为了比较)。我将输入文件分成大小为 numBlocks = inputFileLengt
我是一名优秀的程序员,十分优秀!