6.对象引用、可变性和垃圾回收

1. python中的变量是什么?

python和java的变量本质不一样, python的变量实质上是一个指针 类似便利贴
便利贴过程:
a = 1
# 1.先在内存中生成好了1 
# 2.把a贴在1上面
代码举例:
>>> a = [1, 2, 3]
>>> b = a
>>> print(id(a), id(b))
4329385544 4329385544

>>> print(a is b)
True

2. ==和is的区别

以代码说明:

>>> a = [1, 2, 3, 4]
>>> b = [1, 2, 3, 4]

>>> print(a == b)   # ==其实是调用了__eq__魔法函数
True

>>> print(id(a), id(b))
4400893512 4400893640
>>> print(a is b)   # is判断的是  内存是不是同一地址
False

# 证明 类  在python中是唯一的
>>> class People:
>>>     pass

>>> person = People()
>>> if type(person) is People:
>>>     print('type(person) is People')   
type(person) is People

3. del语句和垃圾回收

python中的垃圾回收是 采用引用技术,当引用计数器为0时,才会删除

>>> a = 1   # 引用计数器为1
>>> b = a   # 引用计数器加1
>>> del a   # 引用计数器减1

>>> print(b)   # del 了a, b依然存在
1

>>> print(a)
Traceback (most recent call last):
  File "6_what_is_var/3_delete.py", line 7, in <module>
    print(a)
NameError: name 'a' is not defined

通魔法函数__del__ 可以自定义 类在被回收时,需要做什么

>>> class A:
>>>     def __del__(self):
>>>         print('__del__ here')

>>> a = A()
>>> del(a)   # 或 del a
__del__ here

3. 一类经典的list参数错误

代码举例1:

>>> def add(a, b):
>>>     a += b
>>>     return a
    
>>> if __name__ == '__main__':
>>>     a = 1
>>>     b = 2
>>>     c = add(a, b)
>>>     print(c)
3
>>>     print(a, b)
1 2

>>>     a = [1, 2]
>>>     b = [3, 4]
>>>     c = add(a, b)
>>>     print(c)
[1, 2, 3, 4]
>>>     print(a, b)    # 传入的参数类型是list时, a的值也改变了
[1, 2, 3, 4]  [3, 4]

>>>     a = (1, 2)
>>>     b = (3, 4)
>>>     c = add(a, b)
>>>     print(c)
(1, 2, 3, 4)
>>>     print(a, b)
(1, 2) (3, 4)

代码举例2:

>>> class Company:
>>>     def __init__(self, name, staffs=[]):
>>>         self.name = name
>>>         self.staffs = staffs

>>>     def add(self, staff_name):
>>>         self.staffs.append(staff_name)

>>>     def remove(self, staff_name):
>>>         self.staffs.remove(staff_name)
        
>>> if __name__ == '__main__':        
>>>     com1 = Company('com1',['cannon1', 'cannon2'])
>>>     com1.add('cannon3')
>>>     com1.remove('cannon1')
>>>     print(com1.staffs)
['cannon2', 'cannon3']

>>>     com2 = Company('com2')
>>>     com2.add('cannon4')

>>>     com3 = Company('com3')
>>>     com3.add('cannon5')

>>>     print(com2.staffs)     # com2  com3 使用了默认的staffs  得到了一样的staffs值
['cannon4', 'cannon5']
>>>     print(com3.staffs)
['cannon4', 'cannon5']

>>>     print(com2.staffs is com3.staffs)   # com2 和 com3 没传入staffs, 默认[]。com2 com3共用了
True

    # 我们可以直接用类 名获取默认的[]
>>>     print(Company.__init__.__defaults__)
(['cannon4', 'cannon5'],)
结论:
  • 为避免以上出现的错误,我应尽量不使用list作为传入参数。即使不得已使用了,也要做好传入参数本身会被改变的准备。

转载于:https://my.oschina.net/u/3836952/blog/1823383

<think>好的,我需要帮助用户在Python中实现SM2加密算法,并处理c1c2c3格式的密文。首先,我得回顾一下用户提供的引用内容,特别是引用[1]、[2]、[3]、[4]中的相关信息。 根据引用[1],用户之前可能接触过国密算法,如SM3和SM4,但这次是SM2。引用[2]提到SM2包括数字签名、密钥交换和加密,这里用户需要的是加密部分。引用[3]详细说明了SM2加密后的密文结构为C1C3C2,即65字节的公钥部分、32字节的摘要和明文长度的密文。而不同语言之间的问题通常是因为ASN.1编码,但用户明确要求生成c1c2c3格式,可能需要避免ASN.1,直接处理原始数据。引用[4]展示了一个Golang的例子,其中提到了C1C2C3的排列方式,可能需要在Python中模仿。 首先,用户想在Python中实现SM2加密,生成C1C2C3格式。我需要考虑现有的库。gmssl库的sm2模块可能是一个起点,但根据引用[1]中的示例,gmssl的sm3_hash被使用,但sm2的加密可能默认使用ASN.1编码,而用户需要原始C1C2C3格式。 查看gmssl的文档,sm2.Encrypt函数可能默认返回ASN.1编码的密文,而不是C1C2C3的拼接。例如,引用[3]指出,OpenSSL使用ASN.1编码,而用户需要的是原始数据。因此,可能需要自定义处理,将各部分拼接成C1C3C2或C1C2C3的顺序。 根据引用[3],SM2密文结构为C1 || C3 || C2,其中C1是65字节(0x04开头,x和y各32字节),C332字节的摘要,C2是明文长度的密文。但引用[4]中的Golang代码使用了sm2.C1C2C3作为参数,可能表示不同的顺序。这里可能存在混淆,需要确认正确的顺序。 需要查阅SM2标准,确认密文结构。根据《SM3密码杂凑算法》相关文档,SM2加密后的密文应该是C1C3C2,即公钥点、SM3摘要、加密后的密文。但不同实现可能有差异,比如有的可能使用C1C2C3。例如,gmssl库的sm2.Encrypt函数可能有一个参数来指定模式,如引用[4]中的sm2.C1C2C3,这可能导致不同的拼接顺序。 因此,可能的解决方案是使用gmssl库,并在加密时指定模式为C1C2C3,然后手动拼接各部分。或者,如果库返回的是ASN.1编码的数据,则需要解析ASN.1结构,提取各部分并按正确顺序拼接。 接下来,我需要检查gmssl的sm2.Encrypt函数的参数。根据引用[4],Golang中的sm2.Encrypt接受一个模式参数,如sm2.C1C2C3。那么在Python的gmssl库中是否有类似的参数?假设存在,那么在Python中调用时指定该模式,可能直接得到正确格式的密文。 假设gmssl的sm2.Encrypt函数返回的是原始拼接的密文,而不是ASN.1编码,那么直接处理即可。但根据引用[3],如果使用OpenSSL或其他库,可能需要处理ASN.1编码,但用户希望避免这种情况,直接生成C1C2C3格式。 另外,用户提供的引用[4]中的Golang代码示例中,加密后的字符串是通过拼接C1C2C3得到的。所以可能需要类似地在Python中处理。 可能的实现步骤: 1. 生成SM2密钥对。使用gmssl的sm2模块生成私钥和公钥。 2. 使用公钥加密明文,指定模式为C1C2C3,得到密文的字节流。 3. 验证密文结构是否为C1 || C2 || C3,或者C1 || C3 || C2,根据库的实现调整。 4. 如果库返回的是ASN.1编码,需要解析并提取各部分,再按正确顺序拼接。 但首先,需要确认gmssl库的sm2.Encrypt函数是否支持指定输出格式。查阅gmssl的文档或源代码,发现sm2.Encrypt可能有参数来控制输出格式。例如,在引用[4]的Golang代码中,模式参数被指定为sm2.C1C2C3,那么在Python的gmssl中可能存在类似选项。 假设在Python的gmssl中,可以传递一个参数来指定模式,例如: encrypt_data = sm2_crypt.encrypt(plaintext, mode=SM2_CIPHERTEXT_MODE.C1C2C3) 如果没有这样的参数,可能需要手动处理。例如,加密后的数据是C1C3C2格式,但用户需要C1C2C3,则需要分割字节并重新排列。 或者,可能gmssl默认返回的是ASN.1编码,因此需要解码。根据引用[3],不同语言的问题源于ASN.1编码的差异,所以如果用户需要原始C1C2C3格式,可能需要避免使用ASN.1,直接拼接各部分。 另外,SM2加密的过程通常包括生成随机公钥C1算密钥派生函数得到对称密钥,加密明文得到C2,并算C3作为摘要。因此,可能需要手动实现这些步骤,而不仅仅依赖库函数。 但手动实现SM2加密较为复杂,涉及椭圆曲线运算、密钥派生函数、哈希等。因此,更实际的方法是使用现有的库,并调整输出格式。 总结可能的解决方案: - 使用gmssl库的sm2模块,调用encrypt方法,并指定输出格式为C1C2C3。 - 如果库不支持指定格式,可能需要解析返回的字节流,分割为C1、C2、C3并重新排列。 - 或者,检查加密后的字节长度是否符合预期,例如65+len(明文)+32,然后手动分割。 例如,如果明文是"ABC123",长度是6字节,那么加密后的总长度应为65+32+6=103字节。根据引用[3],总长度可能为65+32+明文长度=102字节(例如明文5字节时总长度102),所以需要确认各部分长度是否正确。 假设使用gmssl的sm2.Encrypt返回的是C1C3C2格式的原始字节,那么用户需要的是C1C2C3,则需要将中间的C3和C2交换位置。例如,将密文拆分为C1(65字节)、C332字节)、C2(明文长度字节),然后重新拼接为C1 + C2 + C3。 但具体如何分割需要明确各部分的长度。例如,加密后的数据可能结构为:C1(65字节) || C332字节) || C2(n字节)。要转换为C1C2C3格式,就需要将C3和C2的位置交换,变为C1 || C2 || C3。 因此,在Python中,可以这样处理: ciphertext = sm2.encrypt(plaintext) c1 = ciphertext[0:65] c3 = ciphertext[65:97] c2 = ciphertext[97:] desired_ciphertext = c1 + c2 + c3 但需要确认gmssl返回的密文是否确实是这种结构。可能需要实际测试或查阅文档。 此外,根据引用[3]中的描述,原始数据是C1 || C3 || C2,而ASN.1编码的密文则不同。因此,如果gmssl默认返回的是原始数据,那么直接分割即可。如果返回的是ASN.1编码的,则需要解码。 例如,在引用[3]中,使用OpenSSL生成的密文是ASN.1编码的,需要解码才能得到原始C1C3C2。而用户需要的是原始拼接的C1C2C3。因此,可能需要先解码ASN.1,然后重新排列。 但若gmssl的encrypt函数直接返回原始拼接的C1C3C2,而用户需要C1C2C3,则需要手动调整。 综上所述,可能的Python实现步骤如下: 1. 安装gmssl库:pip install gmssl 2. 导入所需模块: from gmssl import sm2, func 3. 生成SM2密钥对: private_key = &#39;00...&#39; # 64字节的16进制字符串 public_key = &#39;04...&#39; # 130字符的16进制字符串,包括04前缀 4. 初始化SM2对象: sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key) 5. 加密明文,并指定模式(如果支持): ciphertext = sm2_crypt.encrypt(b&#39;ABC123&#39;, mode=&#39;C1C2C3&#39;) # 假设存在模式参数 6. 如果没有模式参数,可能需要处理返回的字节: # 假设返回的是C1C3C2格式 c1 = ciphertext[:65] # 65字节 c3 = ciphertext[65:97] # 32字节 c2 = ciphertext[97:] # 明文长度字节 desired_ciphertext = c1 + c2 + c3 7. 将desired_ciphertext转换为十六进制字符串或其他所需格式。 但需要测试gmssl的encrypt函数返回的实际结构。例如,加密后的数据长度是否符合预期。假设明文为"ABC123",长度6字节,加密后的总长度应为65+32+6=103字节。如果实际加密后的长度是103字节,那么可以分割处理。 然而,根据引用[4]中的Golang示例,加密后的字符串是C1C2C3格式,可能gmssl的默认输出已经是该格式,或者需要指定模式。 可能需要查阅gmssl的文档或源代码。例如,查看sm2.py中的encrypt函数定义。假设在sm2.CryptSM2的encrypt函数中,有一个参数可以指定模式,如c1c2c3=True。 假设没有该参数,则可能需要手动调整。 另外,在引用[3]中提到,SM2密文的原始格式是C1 || C3 || C2,而ASN.1编码的密文则是另一种结构。因此,如果gmssl的encrypt返回的是原始格式,那么用户需要的是将C3和 C2的位置交换,变成C1 || C2 || C3。 例如,原始密文是C1(65) + C3(32) + C2(n),用户需要C1 + C2 + C3,所以需要分割并重新拼接。 因此,Python代码可能如下: plaintext = b"ABC123" ciphertext = sm2_crypt.encrypt(plaintext) c1 = ciphertext[:65] c3 = ciphertext[65:97] c2 = ciphertext[97:] desired_ciphertext = c1 + c2 + c3 然后,desired_ciphertext就是C1C2C3格式的密文。 但需要验证gmssl的encrypt函数是否确实返回C1C3C2的结构。例如,使用示例数据测试。 假设用户运行以下代码: from gmssl import sm2, func private_key = &#39;00&#39; * 32 # 示例私钥 public_key = &#39;04&#39; + &#39;00&#39; * 64 # 示例公钥 sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key) ciphertext = sm2_crypt.encrypt(b&#39;abc&#39;) print(len(ciphertext)) # 输出长度 如果明文是3字节(&#39;abc&#39;),则C1是65字节,C332字节,C23字节,总长度100字节。如果输出长度是100,则说明结构正确,可以分割处理。 否则,如果长度不同,可能需要调整分割方式。 总结,可能的实现步骤为: - 使用gmssl库生成密钥对 - 使用encrypt方法加密明文,得到原始密文 - 分割密文为C1、C3、C2 - 重新拼接为C1C2C3格式 最后,用户需要确保在解密时也按照相同的结构处理。例如,解密函数可能需要接收C1C2C3格式,并将其转换为库期望的格式(如C1C3C2),再解密。 此外,引用[3]提到不同语言之间的问题,所以生成C1C2C3格式可能需要与其他系统兼容,确保解密端也使用相同的排列顺序。 因此,最终的Python代码可能如下: from gmssl import sm2, func # 生成密钥对(示例) private_key = &#39;00&#39; * 32 public_key = &#39;04&#39; + &#39;00&#39; * 64 # 假设公钥格式正确 sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key) # 加密 plaintext = b"ABC123" ciphertext = sm2_crypt.encrypt(plaintext) # 分割为C1(65)、C3(32)、C2 c1 = ciphertext[:65] c3 = ciphertext[65:97] c2 = ciphertext[97:] # 重组为C1C2C3 c1c2c3 = c1 + c2 + c3 print("C1C2C3格式密文:", c1c2c3.hex()) 但需要实际测试这段代码,确认分割是否正确,以及加密后的密文结构是否符合预期。 如果gmssl的encrypt函数默认返回的是C1C3C2,那么上述代码将正确重组为C1C2C3。否则,可能需要调整分割的位置。 另外,用户需要注意公钥的正确格式,是否包含0x04前缀,如引用[3]所述,C1部分包括前缀0x04,然后是x和y各32字节,共65字节。 因此,在生成公钥时,需要确保公钥的格式正确,否则加密可能失败。 最后,用户可能还需要处理其他细节,如编码问题、错误处理等,但核心步骤是上述内容。</think>在Python中实现SM2加密算法生成c1c2c3格式密文,可通过以下步骤实现: ### 实现步骤 1. **安装依赖库** ```bash pip install gmssl ``` 2. **密钥生成与加密实现** ```python from gmssl import sm2, func import binascii # 初始化SM2对象(示例密钥) private_key = "00" * 32 # 64位十六进制私钥 public_key = "04" + "00" * 64 # 130位十六进制公钥(含0x04前缀) sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key) # 加密并处理c1c2c3格式 plaintext = b"ABC123" ciphertext = sm2_crypt.encrypt(plaintext) # 分割原始密文(假设库返回C1C3C2格式) c1 = ciphertext[:65] # 公钥点(65字节) c3 = ciphertext[65:97] # SM3摘要(32字节) c2 = ciphertext[97:] # 密文数据(与明文等长) # 重组为c1c2c3格式 c1c2c3 = c1 + c2 + c3 print("C1C2C3格式密文:", binascii.hexlify(c1c2c3).decode()) ``` ### 关键说明 1. **密钥格式** - 公钥需包含`0x04`前缀,后接64字节椭圆曲线坐标(x+y)[^3] - 私钥为32字节十六进制字符串 2. **密文结构** - **C1**:随机生成的临时公钥点(65字节,含`0x04`前缀) - **C2**:加密后的密文数据(长度与明文相同) - **C3**:SM3哈希摘要(32字节)[^3] 3. **跨语言兼容性** - 需确保加解密双方使用**相同字节顺序**(如C1C2C3或C1C3C2) - 若需与其他语言交互,可能需处理ASN.1编码问题[^3] ### 验证解密 ```python # 解密重组后的c1c2c3密文 recovered_plaintext = sm2_crypt.decrypt(c1c2c3) print("解密结果:", recovered_plaintext.decode()) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值