GithubHelp home page GithubHelp logo

gmalg's Introduction

gmalg

Unittest PyPI

国密算法的纯 Python 实现, 不依赖除标准库以外的任何第三方库.

  • 国密体验装
  • 课程作业专供

安装

pip install gmalg

实现的核心算法

  • ZUC 序列密码算法
  • SM2 椭圆曲线公钥密码算法
    • 签名验签
    • 密钥交换
    • 加密解密
  • SM3 密码杂凑算法
  • SM4 分组密码算法
  • SM9 标识密码算法
    • 签名验签
    • 密钥交换
    • 密钥封装
    • 加密解密 (基于密钥派生函数的序列密码算法)

用法

详细文档: gmalg.readthedocs.io

ZUC 生成伪随机密钥流

import gmalg

zuc = gmalg.ZUC(bytes.fromhex("3d4c4be96a82fdaeb58f641db17b455b"),
                bytes.fromhex("84319aa8de6915ca1f6bda6bfbd8c766"))

print(zuc.generate().hex())
print(zuc.generate().hex())

SM3 计算哈希值

import gmalg

sm3 = gmalg.SM3()
print(sm3.value().hex())

sm3.update(b"I'm SM3 algorithm.")
print(sm3.value().hex())

SM4 加密/解密

import gmalg

sm4 = gmalg.SM4(bytes.fromhex("0123456789ABCDEFFEDCBA9876543210"))
cipher = sm4.encrypt(b"0102030405060708")
print(cipher.hex())
print(sm4.decrypt(cipher))

SM2 签名/验签

import gmalg

sm2 = gmalg.SM2(
    bytes.fromhex("3945208F 7B2144B1 3F36E38A C6D39F95 88939369 2860B51A 42FB81EF 4DF7C5B8"),
    b"1234567812345678",
    bytes.fromhex("04 09F9DF31 1E5421A1 50DD7D16 1E4BC5C6 72179FAD 1833FC07 6BB08FF3 56F35020"
                  "CCEA490C E26775A5 2DC6EA71 8CC1AA60 0AED05FB F35E084A 6632F607 2DA9AD13"),
)
msg = b"I'm SM2 sign/verify algorithm."
r, s = sm2.sign(msg)
print(r.hex())
print(s.hex())
print(sm2.verify(msg, r, s))

SM2 加密/解密

import gmalg

sm2 = gmalg.SM2(
    bytes.fromhex("3945208F 7B2144B1 3F36E38A C6D39F95 88939369 2860B51A 42FB81EF 4DF7C5B8"),
    pk=bytes.fromhex("04 09F9DF31 1E5421A1 50DD7D16 1E4BC5C6 72179FAD 1833FC07 6BB08FF3 56F35020"
                    "CCEA490C E26775A5 2DC6EA71 8CC1AA60 0AED05FB F35E084A 6632F607 2DA9AD13"),
)

cipher = sm2.encrypt(b"I'm SM2 encrypt/decrypt algorithm.")
print(cipher.hex())
print(sm2.decrypt(cipher))

SM2 密钥交换

import gmalg

PA = bytes.fromhex("04 160E1289 7DF4EDB6 1DD812FE B96748FB D3CCF4FF E26AA6F6 DB9540AF 49C94232"
                   "4A7DAD08 BB9A4595 31694BEB 20AA489D 6649975E 1BFCF8C4 741B78B4 B223007F")
sm2A = gmalg.SM2(
    bytes.fromhex("81EB26E9 41BB5AF1 6DF11649 5F906952 72AE2CD6 3D6C4AE1 678418BE 48230029"),
    b"abcdefghijklmnopqrstuvwxyz", PA
)

PB = bytes.fromhex("04 6AE848C5 7C53C7B1 B5FA99EB 2286AF07 8BA64C64 591B8B56 6F7357D5 76F16DFB"
                   "EE489D77 1621A27B 36C5C799 2062E9CD 09A92643 86F3FBEA 54DFF693 05621C4D")
sm2B = gmalg.SM2(
    bytes.fromhex("78512991 7D45A9EA 5437A593 56B82338 EAADDA6C EB199088 F14AE10D EFA229B5"),
    b"1234567812345678", PB
)

RA, tA = sm2A.begin_key_exchange()
RB, tB = sm2B.begin_key_exchange()

KB = sm2B.end_key_exchange(16, tB, RA, b"abcdefghijklmnopqrstuvwxyz", PA, gmalg.KEYXCHG_MODE.RESPONDER)
KA = sm2A.end_key_exchange(16, tA, RB, b"1234567812345678", PB, gmalg.KEYXCHG_MODE.INITIATOR)

print(KA == KB)
print(KA.hex())

SM9 签名/验签

import gmalg

hid_s = b"\x01"
msk_s = bytes.fromhex("0130E7 8459D785 45CB54C5 87E02CF4 80CE0B66 340F319F 348A1D5B 1F2DC5F4")
mpk_s = bytes.fromhex("04"
                      "9F64080B 3084F733 E48AFF4B 41B56501 1CE0711C 5E392CFB 0AB1B679 1B94C408"
                      "29DBA116 152D1F78 6CE843ED 24A3B573 414D2177 386A92DD 8F14D656 96EA5E32"
                      "69850938 ABEA0112 B57329F4 47E3A0CB AD3E2FDB 1A77F335 E89E1408 D0EF1C25"
                      "41E00A53 DDA532DA 1A7CE027 B7A46F74 1006E85F 5CDFF073 0E75C05F B4E3216D")
kgc = gmalg.SM9KGC(hid_s=hid_s, msk_s=msk_s, mpk_s=mpk_s)

uid = b"Alice"
sk_s = kgc.generate_sk_sign(uid)

print(sk_s.hex())

sm9 = gmalg.SM9(hid_s=hid_s, mpk_s=mpk_s, sk_s=sk_s, uid=uid)

message = b"Chinese IBS standard"
h, S = sm9.sign(message)

print(h.hex())
print(S.hex())

print(sm9.verify(message, h, S))

SM9 密钥交换

import gmalg

hid_e = b"\x02"
msk_e = bytes.fromhex("02E65B 0762D042 F51F0D23 542B13ED 8CFA2E9A 0E720636 1E013A28 3905E31F")
mpk_e = bytes.fromhex("04"
                      "91745426 68E8F14A B273C094 5C3690C6 6E5DD096 78B86F73 4C435056 7ED06283"
                      "54E598C6 BF749A3D ACC9FFFE DD9DB686 6C50457C FC7AA2A4 AD65C316 8FF74210")
kgc = gmalg.SM9KGC(hid_e=hid_e, msk_e=msk_e, mpk_e=mpk_e)

uid_A = b"Alice"
sk_e_A = kgc.generate_sk_encrypt(uid_A)
print(sk_e_A.hex())

uid_B = b"Bob"
sk_e_B = kgc.generate_sk_encrypt(uid_B)
print(sk_e_B.hex())

sm9_A = gmalg.SM9(hid_e=hid_e, mpk_e=mpk_e, sk_e=sk_e_A, uid=uid_A)
sm9_B = gmalg.SM9(hid_e=hid_e, mpk_e=mpk_e, sk_e=sk_e_B, uid=uid_B)

rA, RA = sm9_A.begin_key_exchange(uid_B)
rB, RB = sm9_B.begin_key_exchange(uid_A)

KB = sm9_B.end_key_exchange(16, rB, RB, uid_A, RA, gmalg.KEYXCHG_MODE.RESPONDER)
KA = sm9_A.end_key_exchange(16, rA, RA, uid_B, RB, gmalg.KEYXCHG_MODE.INITIATOR)

print(KA == KB)
print(KA.hex())

SM9 密钥封装

import gmalg

hid_e = b"\x03"
msk_e = bytes.fromhex("01EDEE 3778F441 F8DEA3D9 FA0ACC4E 07EE36C9 3F9A0861 8AF4AD85 CEDE1C22")
mpk_e = bytes.fromhex("04"
                      "787ED7B8 A51F3AB8 4E0A6600 3F32DA5C 720B17EC A7137D39 ABC66E3C 80A892FF"
                      "769DE617 91E5ADC4 B9FF85A3 1354900B 20287127 9A8C49DC 3F220F64 4C57A7B1")
kgc = gmalg.SM9KGC(hid_e=hid_e, msk_e=msk_e, mpk_e=mpk_e)

uid = b"Bob"

sk_e = kgc.generate_sk_encrypt(uid)
print(sk_e.hex())

sm9 = gmalg.SM9(hid_e=hid_e, mpk_e=mpk_e, sk_e=sk_e, uid=uid)

K, C = sm9.encapsulate(32, uid)  # encapsulate key to self

print(K.hex())
print(C.hex())

print(sm9.decapsulate(C, 32) == K)

SM9 加密/解密

import gmalg

hid_e = b"\x03"
msk_e = bytes.fromhex("01EDEE 3778F441 F8DEA3D9 FA0ACC4E 07EE36C9 3F9A0861 8AF4AD85 CEDE1C22")
mpk_e = bytes.fromhex("04"
                      "787ED7B8 A51F3AB8 4E0A6600 3F32DA5C 720B17EC A7137D39 ABC66E3C 80A892FF"
                      "769DE617 91E5ADC4 B9FF85A3 1354900B 20287127 9A8C49DC 3F220F64 4C57A7B1")
kgc = gmalg.SM9KGC(hid_e=hid_e, msk_e=msk_e, mpk_e=mpk_e)

uid = b"Bob"

sk_e = kgc.generate_sk_encrypt(uid)
print(sk_e.hex())

sm9 = gmalg.SM9(hid_e=hid_e, mpk_e=mpk_e, sk_e=sk_e, uid=uid)

plain = b"Chinese IBE standard"
cipher = sm9.encrypt(plain, uid)  # encrypt data to self

print(cipher.hex())

print(sm9.decrypt(cipher))

更多详细用法可以查看文档.

关于密文顺序

无论是 SM2 还是 SM9, 均遵循国标要求按照 C1|C3|C2 的顺序构造和解析密文字节流.

但是在计算各部分数值的时候, 代码里是没有顺序的, 仅仅按照三个独立的 C1, C2, C3 对象返回, 这与密文字节流的构造是分开的.

关于 PC 字节

在 SM2/SM9 算法中, 当椭圆曲线上的点转换成字节串时, 需要在开头附加一个字节 PC 加以标识, 非无穷远点按国标要求有三类表示模式:

  • 压缩表示形式, PC = 0x020x03
  • 未压缩表示形式, PC = 0x04
  • 混合表示形式, PC = 0x060x07

gmalg 中所有需要将椭圆曲线上的点转换成字节串时, 一定带有 PC 标识字节, 但是部分其他项目代码在实现时可能只实现了未压缩表示形式 (PC = 0x04), 并且可能在提供参数时省略了开头的 PC 字节, 因此在使用时需要注意甄别.

可能涉及密文, 公钥, 随机点等参数的字节串表示形式.


If you think this project is helpful to you, ⭐ it and let more people see!

gmalg's People

Contributors

ww-rm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

gmalg's Issues

SM2密钥交换

图片
能不能把这个r(临时私钥)作为begin_key_exchange()的输入,为None时随机生成,同时return的时候也带上r,这样可以更好的学习和验证整个过程,现在拿不到这个临时私钥。

sm2密钥交换问题

我按照测试用例重新写了一个函数,可以自己控制临时私钥,测试过程中发现,uid都是默认值31323334353637383132333435363738的时候,计算结果正常,和其他工具的结果也对得上,但是把uid换成自定义的以后,协商出来的密钥就不一样了
图片

图片

def sm2keyexchange(sk_a, sk_a_temp, uid_a, sk_b, sk_b_temp, uid_b, klen):
klen = 16
sk_a = bytes.fromhex(sk_a)
sk_b = bytes.fromhex(sk_b)
sk_a_temp = int(sk_a_temp, 16)
sk_b_temp = int(sk_b_temp, 16)
pk_a = gmalg.SM2().generate_pk(sk=sk_a)
pk_b = gmalg.SM2().generate_pk(sk=sk_b)
uid_a = uid_a.encode("utf-8")
uid_b = uid_b.encode("utf-8")
sm2A = gmalg.SM2(sk_a, uid_a, pk_a, rnd_fn=lambda _: sk_a_temp)
sm2B = gmalg.SM2(sk_b, uid_b, pk_b, rnd_fn=lambda _: sk_b_temp)
RA, tA = sm2A.begin_key_exchange()
RB, tB = sm2B.begin_key_exchange()
KB = sm2B.end_key_exchange(klen, tB, RA, uid_b, pk_a, gmalg.KEYXCHG_MODE.RESPONDER)
KA = sm2A.end_key_exchange(klen, tA, RB, uid_a, pk_b, gmalg.KEYXCHG_MODE.INITIATOR)
return KA, KB

sk_a = '264c35c1da0dd1b6a705c036cff29b0a541f303a66a6d0cb92f2376e87984903'
sk_a_temp = '5b0eb96ba076ed880c1caa3eed939879138e6ea9910bd3db609dd04c465157bf'
uid_a = 'alice'
sk_b = '4632d797236e0173047c83cb056dac6bdbbdbef34c1697edb47b64cdedd3939f'
sk_b_temp = '46dc55b1474641e25a8fd070daff288a8d12d91ccfdc2ed0f78c6ceda7ff71f5'
uid_b = 'white'
klen = 16
ka, kb = sm2keyexchange(sk_a, sk_a_temp, uid_a, sk_b, sk_b_temp, uid_b, klen)
print(ka.hex())
print(kb.hex())

ka:81396b31831d7216c6d83f59d5b4510c
kb:3b79d4cc40d4ace5b81f3bd461a3894d

uia_a和uid_b的位置搞反了,关闭

sm2的实现有两个问题

第一个问题是密文的排列,按照GB/T 32918.4-2016 信息安全技术 SM2椭圆曲线公钥密码算法 第4部分:公钥加密算法的规定,密文的排列应该是C1C3C2
图片

第二个问题是计算Z值使用的id,如果不指定ID,默认使用1234567812345678,GB-T 35276-2017 信息安全技术 SM2密码算法使用规范
图片

sm2私钥计算公钥问题

我有一个私钥
hex:5f10c8b55b530898c4f95f851417e78e3c92400f73ff3f556346d1be6f0008f
dec:2687460962942752655476196615361824446058989685087458871033485227498287399055
用这个私钥计算公钥,KA = gmalg.SM2().generate_pk(bytes.fromhex(K)),计算时报错。
ValueError: non-hexadecimal number found in fromhex() arg at position 63

国标给的私钥范围,我看了下我这个私钥应该是符合的。
d∈[1,n-2],从1到115792089210356248756420345214020892766061623724957744567843809356293439045921

SM2解密相关

SM2解密

sk = bytes.fromhex('4A1ED9ED547F5B957033A17D126AC8A3A53A81AA28458BF0F9C4D5E59823D970')

密文,密文前面的04是我手动加上去的

cipher_text = bytes.fromhex('044B3E911512FD8229C728F5F7DCEA2FFEA328A3E00F633584EBD5C07C7AD62751CC8FE24A275C7C2EB4585B14A673B72CEA871B28D4524D0268A0CDEA554973D25D034079BBB81B483AC4D029C40762F3C5FF187A071CE1F9820AB7DF89A83357273FAF5B3D7A5FFF98169288BCF855B9')
sm2_decrypt_outside = gmalg.SM2(sk=sk)
plain = sm2_decrypt_outside.encrypt(sk)
print('SM2解密出的数据:', plain.hex())

SM2解密出的数据:0406c4d7089bcc6153212c517ad057f94545168cc2c79328f4cb38c7b504f0b43de0297369ad81b35fe514bbabed46ceb3ed25d8bc4118d1bad18684b73f66471f067fe8928462afe986658e1fd0a9375475efc7c5b64d8e8d78ed930f34419f8c32e24604a65a35c130a4a4cd17932cd2f8521587812bda962f10d8c9039e3361

正确答案应该是:D1968C224CAD0C59EA860EA2FB110EA5
这是我们的一道考题,试了好多工具都解不出来,最后在https://the-x.cn/cryptography/Sm2.aspx解出了正确答案。
图片

SM9密文顺序问题

图片
我看代码里面return的是C1, C2, C3,C2是不定长的,放在中间无法校验密文的合法性。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.