对称密码算法,对str的操作,封装了 symmetric_alg.py

"""symmetric_apply.py 对 symmetric_alg.py 进行了封装
Author: tanglei
DateTime:2024-11-18 完成
微信:ciss_cedar
欢迎一起学习
"""
import base64

from utils.algorithm.symmetric.symmetric_alg import MySymCipher, AlgName, CipherMode

code_tuple = ('Hex', 'base64')
alg_tuple = ('TripleDES', 'Blowfish', 'CAST5', 'IDEA')
Des_3 = 'TripleDES'


def symmetric_encrypt(key, iv, source, mode, alg_name, code=code_tuple[0]):
    if len(key) >= 32 and alg_name == Des_3:
        # key 传入16字节【32字符】,iv传入16字节【字符】
        key = key[:32] + key[:16]  # 可以为48字符,ABA模式的key

    if len(iv) >= 16 and alg_name in alg_tuple:
        iv = iv[:16]

    key_bytes = bytes.fromhex(key)
    iv_bytes = bytes.fromhex(iv)
    plain_bytes = source.encode()
    my_alg = MySymCipher(key_bytes, iv_bytes, mode, alg_name)
    encrypt_bytes = my_alg.encrypt_bytes(plain_bytes)
    if code == code_tuple[0]:
        enc_source = encrypt_bytes.hex().upper()
    else:
        enc_source = base64.b64encode(encrypt_bytes).decode()
    return enc_source


def symmetric_decrypt(key, iv, enc_source, mode, alg_name, code=code_tuple[0]):
    # key 传入16字节【32字符】,iv传入16字节【字符】
    if len(key) >= 32 and alg_name == Des_3:
        # key 传入16字节【32字符】,iv传入16字节【字符】
        key = key[:32] + key[:16]  # 可以为48字符,ABA模式的key

    if len(iv) >= 16 and alg_name in alg_tuple:
        iv = iv[:16]

    key_bytes = bytes.fromhex(key)
    iv_bytes = bytes.fromhex(iv)
    if code == code_tuple[0]:
        cipher_bytes = bytes.fromhex(enc_source)
    else:
        cipher_bytes = base64.b64decode(enc_source)
    my_alg = MySymCipher(key_bytes, iv_bytes, mode, alg_name)
    decrypt_bytes = my_alg.decrypt_bytes(cipher_bytes)
    source = decrypt_bytes.decode()
    return source


def gen_key(length=16):
    # 使用软件算法,可以调用系统函数或者使用secrets生成随机数再进行派生
    # 当前使用32字符,16字节的随机数也是可以的。
    random_bytes = MySymCipher.gen_random_bytes(length)
    key = random_bytes.hex().upper()
    return key


def gen_iv(length=16):
    # 使用软件算法,可以调用系统函数或者使用secrets生成随机数再进行派生
    # 当前使用32字符,16字节的随机数也是可以的。
    random_bytes = MySymCipher.gen_random_bytes(length)
    iv = random_bytes.hex().upper()
    return iv


def gen_key_iv(length=16):
    # 使用软件算法,可以调用系统函数或者使用secrets生成随机数再进行派生
    # 当前使用32字符,16字节的随机数也是可以的。
    random_bytes = MySymCipher.gen_random_bytes(length)
    key = random_bytes.hex().upper()

    random_bytes = MySymCipher.gen_random_bytes(length)
    iv = random_bytes.hex().upper()
    return key, iv


def main():
    key128 = '2934412A66B7A186DC35DC40E926F9EE'
    key192 = '2934412A66B7A186DC35DC40E926F9EE2934412A66B7A186'
    key256 = '2934412A66B7A186DC35DC40E926F9EE2934412A66B7A186DC35DC40E926F9EE'
    # AES key长度变化iv都是128位
    iv = '86CD720D75F4622DBE96078A3CD1076E'

    # key = key192
    source = '1'

    alg_name = AlgName.AES.value
    mode = CipherMode.CBC.value
    cipher = symmetric_encrypt(key128, iv, source, mode, alg_name)
    plain = symmetric_decrypt(key128, iv, cipher, mode, alg_name)
    print(f'alg_name={alg_name},mode={mode}')
    print(f'key={key128},iv={iv}')
    print(f'source=', source)
    print(f'cipher={cipher}')
    print(f'plain={plain}')
    cipher = symmetric_encrypt(key192, iv, source, mode, alg_name)
    plain = symmetric_decrypt(key192, iv, cipher, mode, alg_name)
    print(f'cipher={cipher}')
    print(f'plain={plain}')
    cipher = symmetric_encrypt(key256, iv, source, mode, alg_name)
    plain = symmetric_decrypt(key256, iv, cipher, mode, alg_name)
    print(f'cipher={cipher}')
    print(f'plain={plain}')

    print('-' * 66)
    # code = 'base64'
    # cipher =symmetric_encrypt(key,iv,source,mode,alg_name,code)
    # plain = symmetric_decrypt(key,iv,cipher,mode,alg_name,code)
    # print(f'alg_name={alg_name},mode={mode},code={code}')
    # print(f'key={key},iv={iv}')
    # print(f'source=', source)
    # print(f'cipher={cipher}')
    # print(f'plain={plain}')
    result = ''
    # ALG_NAME = ('TripleDES', 'AES', 'SM4')
    # MODE_NAME = ('ECB',)  # ('ECB', 'CBC')
    # code_tuple = ('Hex',)  # ('Hex', 'base64')
    # for alg_name in ALG_NAME:
    #     for mode_name in MODE_NAME:
    #         for code in code_tuple:
    #             if alg_name == 'TripleDES' and mode_name == 'CBC':
    #                 tempkey = key
    #                 tempiv = iv
    #                 key = key + key[0:16]
    #                 iv = iv[0:16]
    #                 result_value = symmetric_encrypt(key, iv, source, mode_name, alg_name, code)
    #                 length = len(result_value)
    #                 result += f'{alg_name}_{mode_name}_{code}' + f'({length}|{length / 2.0}|{length / 2.0 * 8})=' + result_value + '\n'
    #                 iv = tempiv
    #                 key = tempkey
    #             else:
    #                 result_value = symmetric_encrypt(key, iv, source, mode_name, alg_name, code)
    #                 length = len(result_value)
    #                 result += f'{alg_name}_{mode_name}_{code}' + f'({length}|{length / 2.0}|{length / 2.0 * 8})=' + result_value + '\n'
    #         result += '-' * 99 + '\n'


if __name__ == '__main__':
    main()
<think> 我们面对的问题是:在distance_utils.py中尝试使用相对导入`from ..common_used import seeds`来导入common_used目录下的seeds.py模块时,出现了`ImportError: attempted relative import with no known parent package`错误。 ### 问题分析 这个错误通常发生在Python的相对导入中,当当前模块(这里是distance_utils.py)没有被识别为一个包的一部分时。相对导入要求模块位于一个包内,并且我们是在这个包的结构中运行的。 假设我们的项目结构如下(根据问题描述推断): ``` project/ ├── common_used/ │ ├── __init__.py │ └── seeds.py └── utils/ ├── __init__.py └── distance_utils.py ``` 这里,`common_used`和`utils`应该是两个并列的目录(包)。在`distance_utils.py`中,我们试图使用`from ..common_used import seeds`来导入上一级目录下的`common_used`包中的`seeds`模块。 ### 错误原因 1. **相对导入没有父包**:Python解释器不知道当前模块(distance_utils.py)属于哪个顶层包。这通常是因为我们直接运行了该脚本(作为主模块),或者执行环境没有正确设置包的上下文。 2. **执行方式问题**:如果我们直接运行`distance_utils.py`(例如:`python distance_utils.py`),那么它将被视为顶级模块,此时`..`(上一级)没有包可以引用。 3. **包结构问题**:确保每个目录(包)都有`__init__.py`文件(可以是空文件),这样Python才会将其视为包。 ### 解决方案 #### 方案1:使用绝对导入 在包内部,我们推荐使用绝对导入,这样可以避免相对导入的很多问题。假设我们的顶层包名为`project`(即项目根目录),那么我们可以这样导入: ```python from common_used import seeds ``` 但是,这要求我们的项目根目录必须在Python的模块搜索路径中(sys.path)。通常,当我们运行一个位于项目根目录下的主程序时,根目录会被自动添加到sys.path。 然而,如果`utils`和`common_used`不是同一个顶级包下的子包(例如,它们都在一个名为`project`的顶级包下),那么我们需要将顶级包路径加入sys.path,或者使用完整的绝对导入路径。 #### 方案2:调整运行方式 如果我们确实需要使用相对导入,那么应该确保不要直接运行包内的模块(如distance_utils.py)。相反,我们应该在包外部运行一个主脚本,通过这个主脚本来调用包内的模块。 例如,在项目根目录下创建一个`main.py`: ```python from utils.distance_utils import some_function if __name__ == '__main__': some_function() ``` 然后运行:`python main.py` 这样,当我们运行`main.py`时,Python会将项目根目录(即`project`)添加到sys.path,并且`utils`和`common_used`都作为顶级包`project`下的子包,因此相对导入和绝对导入都能正常工作。 #### 方案3:修改导入语句(相对导入的替代写法) 在`distance_utils.py`中,我们也可以尝试使用以下相对导入方式(但同样需要确保在包内运行): ```python from ...common_used import seeds # 如果project是顶级包,且utils和common_used是同级目录,那么这里应该是两个点还是三个点? ``` 实际上,对于如下结构: ``` project/ (顶级包) ├── common_used/ └── utils/ ``` 在`utils/distance_utils.py`中,要导入`common_used`,应该使用: ```python from .. import common_used # 然后通过common_used.seeds使用 # 或者 from ..common_used import seeds ``` 注意,这里用两个点,因为`utils`和`common_used`是同一级(都在顶级包`project`下)。 #### 方案4:动态修改sys.path(不推荐,但有时快速解决) 在`distance_utils.py`中,我们可以动态地将项目根目录添加到sys.path: ```python import sys import os # 获取当前文件所在目录的父目录的父目录(即项目根目录) project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if project_root not in sys.path: sys.path.insert(0, project_root) # 然后使用绝对导入 from common_used import seeds ``` 这种方法虽然可行,但破坏了包的封装性,并且可能导致路径混乱,所以一般作为临时解决方案。 ### 推荐做法 1. 确保项目结构清晰,使用包结构(每个目录都有`__init__.py`文件)。 2. 使用绝对导入(从顶级包开始导入),并在项目根目录运行主程序,这样所有导入都能正常工作。 3. 避免直接运行包内部的模块(除非有特殊需要,并且了解其中的机制)。 根据你的项目结构,如果你的项目根目录(包含`common_used`和`utils`的目录)没有被Python识别为包,那么你需要确保在运行程序时,项目根目录在Python的搜索路径中。 ### 实际操作 如果上述方案仍然不能解决,请检查: - 项目目录结构。 - 是否存在`__init__.py`文件。 - 运行时的当前工作目录和Python路径。 如果问题依旧,请提供更详细的项目结构和你运行脚本的方式,以便进一步分析。 ### 相关问题 1. 如何在Python中正确设置包的相对导入结构? 2. 绝对导入和相对导入各有什么优缺点? 3. 如何将项目根目录永久添加到Python的搜索路径? 4. 在大型项目中如何组织模块和包以避免导入错误? </think> 要解决在 `distance_utils.py` 中使用 `from ..common_used import seeds` 导入时出现的 `ImportError: attempted relative import with no known parent package` 错误,需要调整包结构和导入方式。以下是详细解决方案: ### 错误原因分析 1. **相对导入问题**:`..` 表示上级包,但 Python 无法识别当前模块的父包 2. **包结构缺陷**:缺少 `__init__.py` 文件或包层级关系未正确定义 3. **执行环境问题**:直接运行脚本而非作为模块导入 ### 解决方案 #### 方法1:完善包结构(推荐) ```diff 项目目录/ ├── common_used/ │ ├── __init__.py # 新增空文件 │ └── seeds.py ├── utils/ │ ├── __init__.py # 新增空文件 │ └── distance_utils.py └── main.py # 新增入口文件 ``` 在 `distance_utils.py` 中使用绝对导入: ```python from project.common_used import seeds # 假设项目目录是顶级包 ``` #### 方法2:动态路径修改(临时方案) 在 `distance_utils.py` 开头添加: ```python import sys import os # 获取上级目录路径 sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) from common_used import seeds ``` #### 方法3:改用绝对导入(需确认包名) ```python # 假设你的顶级包名是 "my_project" from my_project.common_used import seeds ``` ### 关键步骤 1. **创建 `__init__.py` 文件** 在每个目录下创建空文件: ```bash touch common_used/__init__.py touch utils/__init__.py ``` 2. **修改入口执行方式** 通过主模块调用而非直接运行子模块: ```python # main.py 内容 from utils.distance_utils import your_function if __name__ == "__main__": your_function() ``` 执行命令: ```bash python main.py ``` 3. **检查包安装状态** 如果使用开发模式安装: ```bash pip install -e . ``` ### 验证方法 在 Python 解释器中测试导入: ```python >>> import utils.distance_utils >>> from common_used.seeds import your_function # 应正常导入 ``` ### 注意事项 1. 相对导入 (`..`) 只能在包内部使用,不能用于顶层脚本 2. PyCharm/VSCode 等编辑器可能自动添加根目录到路径,但生产环境需显式处理 3. 对于复杂项目,建议使用 `setuptools` 创建 `setup.py` 规范安装 > 包结构设计应遵循 PEP 328 规范,顶层包应包含所有子模块[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值