吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2232|回复: 17
收起左侧

[Python 原创] 常见编码和加密(python和JavaScript使用示例)

  [复制链接]
天空宫阙 发表于 2023-6-23 19:49

常见编码和加密

编码

ASCII码

Base64

Hex

Base64 Hex 对二进制数据的一种编码方式,不属于加密,但加密后一般需要对数据进行编码Base64 Hex比较常见。

信息摘要(哈希)

md5

import hashlib
m = hashlib.md5()
m.update('hello world'.encode('utf-8'))
print(m.hexdigest())
const CryptoJS = require("crypto-js");
console.log(CryptoJS.MD5('hello world').toString())

SHA1
SHA256

SHA1 SHA256 也可分别使用python的hashlib库和JavaScript的crypto-js实现,使用方法类似

加密

AES加密

DES加密

算法 密钥长度 工作模式 填充模式
AES 56/64 ECB/CBC/PCBC/CTR NoPadding/ZeroPadding/PKCS5Padding/
DES 128/192/256 ECB/CBC/PCBC/CTR NoPadding/PKCS5Padding/PKCS7Padding

python和javascript使用AES/CBC/PKCS7的代码如下

 from Crypto.Cipher import AES  # pip install pycryptodome
 import base64
 import binascii

 def encrypt(k, iv, content):
     # k:密钥,iv:偏移量,content:需加密的内容
     k = k.encode("utf-8")
     iv = iv.encode("utf-8")
     # pad = lambda s: s + (16 - len(s)%16) * chr(0) # AES加密时,明文长度需为16的倍数。这里的pad用来填充,chr(0)表示为ZeroPadding,在最后填充0直到长度为16的倍数
     pad = lambda s: s + (16 - len(s)%16) * chr(16 - len(s)%16) # 这里为Pkcs7填充
     content = pad(content).encode("utf-8")
     cipher = AES.new(k, AES.MODE_CBC, iv)  # CBC模式加密,还有ECB模式
     cipher_text = cipher.encrypt(content)
     # enc = base64.b64encode(cipher_text).decode("utf-8")
     enc = binascii.b2a_hex(cipher_text).decode("utf-8")
     return enc

 k = "1234567890abcDEF"
 iv = "1234567890abcDEF"
 print(encrypt(k, iv, "hello world"))
const CryptoJS = require("crypto-js");

var k = CryptoJS.enc.Utf8.parse('1234567890abcDEF'); // 密钥
var iv = CryptoJS.enc.Utf8.parse('1234567890abcDEF'); // iv

var encrypted = CryptoJS.AES.encrypt("hello world", k, {
    mode: CryptoJS.mode.CBC,
    iv: iv,
    padding: CryptoJS.pad.Pkcs7, // Pkcs7填充
}).toString()
console.log('base64',encrypted)
var e64 = CryptoJS.enc.Base64.parse(encrypted);
var eHex = e64.toString(CryptoJS.enc.Hex);
console.log('hex',eHex)

AES的其他模式和填充方式使用方法类似

ECB模式无iv值

AES对密钥的长度有限制,可以为16字节,24字节或者32字节,有时用户输入的密钥不满足长度的要求,crypto-js库的默认做法是根据输入密钥和随机数,利用md5生成新密钥和iv值

var encrypted = CryptoJS.AES.encrypt("Message", "Secret Passphrase");

var decrypted = CryptoJS.AES.decrypt(encrypted, "Secret Passphrase");

以上crypto-js库默认AES加密的python实现

import base64
from Crypto.Cipher import AES
from Crypto import Random
from hashlib import md5

"""
pip install pycryptodome
"""

def pad(s):
    return s + (16 - len(s) % 16) * chr(16 - len(s) % 16).encode()

def unpad(s):
    return s[0:-ord(s[len(s)-1:])]

def bytes_to_key(data, salt, output=48):
    assert len(salt) == 8, len(salt)
    data += salt
    key = md5(data).digest()
    final_key = key
    while len(final_key) < output:
        key = md5(key + data).digest()
        final_key += key
    return final_key[:output]

def encrypt(data, passphrase):
    salt = Random.new().read(8)
    key_iv = bytes_to_key(passphrase, salt, 32+16)
    key = key_iv[:32]
    iv = key_iv[32:]
    aes = AES.new(key, AES.MODE_CBC, iv)
    cipherbyte = base64.b64encode(b"Salted__" + salt + aes.encrypt(pad(data)))
    return cipherbyte

def decrypt(data, passphrase):
    data = base64.b64decode(data)
    assert data[:8] == b'Salted__'
    salt = data[8:16]
    key_iv = bytes_to_key(passphrase, salt, 32+16)
    key = key_iv[:32]
    iv = key_iv[32:]
    aes = AES.new(key, AES.MODE_CBC, iv)
    plainbyte = unpad(aes.decrypt(data[16:]))
    return plainbyte

if __name__ == '__main__':
    data = "Message".encode()
    passphrase = "Secret Passphrase".encode()
    encrypt_data = encrypt(data, passphrase)
    print(encrypt_data)

RSA加密

填充方式 待填充长度 填充后长度
RSA_NO_PADDING 不填充 和公钥等长
RSA_PKCS1_PADDING 至少RSA_size(rsa) - 11 和公钥等长
RSA_PKCS1_OAEP_PADDING RSA_size(rsa) - 41 和公钥等长

RSA_PKCS1_PADDING 相同明文每次加密结果不同

import rsa
import binascii

# 生成RSA公钥和私钥
(publickey, privkey) = rsa.newkeys(1024)
# rsa使用的是RSA_PKCS1_PADDING
m = rsa.encrypt('hello world'.encode(), publickey)
encrypted_data = m.hex()
print(encrypted_data)
decrypted_data = rsa.decrypt(binascii.a2b_hex(encrypted_data) ,privkey)
print(decrypted_data)

RSA_NO_PADDING 相同明文每次加密结果相同

import rsa

class Encrypt():
    """
    该类为参考的这篇文章:https://www.52pojie.cn/forum.php?mod=viewthread&tid=874374
    主要用于对应JS中的RSAKeyPair的RSA加密,每次对相同明文加密后的密文都是相同的,原因为NoPadding
    """
    def __init__(self, e, n):
        self.e = e
        self.n = n

    def encrypt(self, message):
        ee = int(self.e, 16)
        nn = int(self.n, 16)
        rsa_pubkey = rsa.PublicKey(e=ee, n=nn)
        crypto = self._encrypt(message.encode(), rsa_pubkey)
        return crypto.hex()

    def _pad_for_encryption(self, message, target_length):
        message = message[::-1]
        max_msglength = target_length - 11
        msglength = len(message)

        padding = b''
        padding_length = target_length - msglength - 3

        for i in range(padding_length):
            padding += b'\x00'

        return b''.join([b'\x00\x00',padding,b'\x00',message])

    def _encrypt(self, message, pub_key):
        keylength = rsa.common.byte_size(pub_key.n)
        padded = self._pad_for_encryption(message, keylength)

        payload = rsa.transform.bytes2int(padded)
        encrypted = rsa.core.encrypt_int(payload, pub_key.e, pub_key.n)
        block = rsa.transform.int2bytes(encrypted, keylength)

        return block

def USE_RSA(message):
    e = "010001"
    n = "81eb7e93bc0e458f67ad208ffb8039a139dffab9b576309212b6c5b411c0f32266ab8700c617562f294abda31f1195163a058637dfebeb80fa0b8cfa0ef63fac3a52b8c3ecf26cb334745d4c850cb5c7fd0bac81ce39e8814c7284fa8bc9721d66189fe5c6d7a3b1046cfdecc4e2976238ccc0a8a6ebbf0ebdedf4737d2dfc99"
    en = Encrypt(e, n)
    return en.encrypt(message)

ciphertext = USE_RSA("111111")
print(ciphertext)

RSA 密钥的参数和导入方式

RSA 密钥的参数

  1. 公钥参数:
    • n:模数(modulus),通常为两个大素数的乘积。
    • e:指数(exponent),用于加密操作。
  2. 私钥参数:
    • n:模数(modulus),与公钥中的模数相同。
    • d:私钥指数(private exponent),用于解密操作。

python中RSA 密钥导入方式可以使用RSA.import_key(private_key_str)也可以使用RSA.construct((private_key.n,private_key.e,private_key.d)),本质上是一样的可以根据方便程度选择。

from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes
import binascii

sentinel = get_random_bytes(16)

private_key_str = """-----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQCB636TvA5Fj2etII/7gDmhOd/6ubV2MJIStsW0EcDzImarhwDG
F1YvKUq9ox8RlRY6BYY33+vrgPoLjPoO9j+sOlK4w+zybLM0dF1MhQy1x/0LrIHO
OeiBTHKE+ovJch1mGJ/lxtejsQRs/ezE4pdiOMzAqKbrvw697fRzfS38mQIDAQAB
AoGAYWca+Muur3v6MJQPHnFdw4BOaf09DKURfrJEuuHslNwfuU13yQvJ84WzoUVg
j6AEj++AVvesOl3yGSLR+OIBnqMFZvs6MjBzn5RdKjD3PiiBdUgBh+bGA+9peeqo
8E0FBiPLkedXorM1YtR39cxPPhreNO/R+ApMLA/Z3RZDeWECRQCypZ9xrqWTMYDg
imfyQbKyX2F1ow/fyC29G/ysuT/x8TyiJwWR0QjKEYA1H1G+jEZALJj2H/N9rUFk
ad6ZmN5lPfBCDQI9ALospps+/QyVQl6yIp13XskhjGOhhyzmEOlkeOJbDcy+eLey
ND8jj32YhNMXe29r/InC6msuuLIo9ujdvQJEMzg1PLzcEBWzY62LG/QmLeoW4Ul9
NaYJJx0tFsCOSunlfoA9oo8SPA1Eevad00oYojGnMXn7r97KzuVjwxoHOXPGvMkC
PCxmpb10wkkT9+Y5ucOwSmzRkXfZeDGfFP10ttfVO29PJd85ovhD9N7RVyw493lV
Wb9JOzsgw2/KEUjsSQJEWrAxPbERzSsM+syfrcOhs424v4m97v10kdYXcpuWuAuy
v8yozU2CM1cFEg3CxNJEw1dF9bHon2LJtz2W6gjDLtm9y4I=
-----END RSA PRIVATE KEY-----"""
# 私钥导入方式1
private_key = RSA.import_key(private_key_str)
print('数模n(16进制)',hex(private_key.n)[2:])
print('指数e(16进制)',hex(private_key.e)[2:])
print('私钥指数private exponent d(16进制)',hex(private_key.d)[2:])

# 私钥导入方式2
private_key2 = RSA.construct((private_key.n,private_key.e,private_key.d))
cipher_rsa = PKCS1_v1_5.new(private_key2)
# 密文
encrypted_data = '1d8a3e73f4179e20a9328fe17551d99aa92e0a510c382dec4e03f0d0f4d38e81580748fcce4c6c1361b65ca8010e9eaa8d274b2def2390e00b3b5748da099d3376cf9a43845c52b1f91c4b6a40caf40bc26ef8e8fa98e226afdcca8b8304f8cb4c6e8e336436f0f809f70b65c7f9acd0d7aab25d7b9de89458c9622e6f815477'
decrypted_data = cipher_rsa.decrypt(binascii.a2b_hex(encrypted_data),sentinel=sentinel)
print(decrypted_data)

参考链接
https://github.com/DingZaiHub/PythonSpider/tree/master/00-%E9%80%9A%E7%94%A8%E5%8A%A0%E5%AF%86
https://www.bilibili.com/video/BV16e4y1G7xv?p=27

免费评分

参与人数 8吾爱币 +15 热心值 +8 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Anonymous520 + 1 + 1 我很赞同!
echoaku + 1 + 1 我很赞同!
helian147 + 1 + 1 热心回复!
degas8888 + 1 + 1 热心回复!
prince_cool + 2 + 1 我很赞同!
yjn866y + 1 + 1 谢谢@Thanks!
ccwuax + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Arctic7 发表于 2023-6-24 15:58
自己在公司内源项目写了完整的JS加解密方法,包括AES-CCB AES-GCM,ECC,SHA256等等,cryptojs只能解决一部分问题,最核心的随机数生成还是用的nodejs原生的crypto模块
 楼主| 天空宫阙 发表于 2023-6-25 18:41
Arctic7 发表于 2023-6-24 15:58
自己在公司内源项目写了完整的JS加解密方法,包括AES-CCB AES-GCM,ECC,SHA256等等,cryptojs只能解决一部 ...

公司做什么的?爬虫还是nodejs的后端,前端的加密要省事一般用cryptojs,要安全性高一般要魔改加密并添加混淆了
52Mxw 发表于 2023-6-23 20:36
yjn866y 发表于 2023-6-23 21:58
必须一加分
redfieldw 发表于 2023-6-23 22:04
感谢科普,收藏
d5850951556 发表于 2023-6-23 22:26
看着这些代码,头疼……
头像被屏蔽
moruye 发表于 2023-6-23 23:21
提示: 作者被禁止或删除 内容自动屏蔽
89684828 发表于 2023-6-24 07:27
谢谢楼主,期待更好的作品!
头像被屏蔽
jinzhu160 发表于 2023-6-24 08:19
提示: 作者被禁止或删除 内容自动屏蔽
zhengsg5 发表于 2023-6-24 10:53
非常不错,多谢分享!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 21:27

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表