BC库实现SM2解密时InvalidCipherTextException

BC库实现SM2解密时InvalidCipherTextException: invalid cipher text

问题描述

在不同系统之间的国密SM2加密解密联调时,出现InvalidCipherTextException。笔者的BC(bouncycastle)库版本如下:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.65</version>
    </dependency>

问题产生原因

  1. 公私钥不匹配
  2. 密文内容发生了变化
  3. 密文的格式不一致
    前两个原因的排除较为简单。第三个原因主要是由于不同系统的SM2实现方案不一致,早期版本的SM2密文格式为C1C2C3.(C1为椭圆曲线坐标点 两个32位的BigInteger;C2是密文,长度与原文一致;C3是对密文做SM3摘要计算后的值)。而新版本的密文格式为C1C3C2.BC库版本的默认密文格式为C1C2C3,因此需要设置密文格式。查看源码发现1.65版本是提供了两种方案的,只需要在实例化的时候传入Mode即可。

public class SM2Engine
{
    public enum Mode
    {
        C1C2C3, C1C3C2;
    }

    private final Digest digest;
    private final Mode mode;
    
    private boolean forEncryption;
    private ECKeyParameters ecKey;
    private ECDomainParameters ecParams;
    private int curveLength;
    private SecureRandom random;

解决方案

实例化时传入Mode类型。

SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现SM2算法需要用到椭圆曲线加密算法和哈希算法,这里我们使用Python内置的`hashlib`和`cryptomath`模块来实现。 首先,我们需要定义椭圆曲线的参数和基点: ```python P = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF A = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC B = 0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93 N = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123 Gx = 0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE171BEEB6E3A9D4F5B Gy = 0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A ``` 然后,我们需要实现点加和点倍运算: ```python def add(p1, p2): if p1 is None: return p2 if p2 is None: return p1 x1, y1 = p1 x2, y2 = p2 if x1 == x2 and y1 != y2: return None if x1 == x2: m = (3 * x1 * x1 + A) * cryptomath.invmod(2 * y1, P) % P else: m = (y1 - y2) * cryptomath.invmod(x1 - x2, P) % P x3 = (m * m - x1 - x2) % P y3 = (m * (x1 - x3) - y1) % P return (x3, y3) def mul(k, p): if k == 0 or p is None: return None if k == 1: return p if k % 2 == 0: return mul(k // 2, add(p, p)) else: return add(p, mul(k - 1, p)) ``` 接下来,我们需要实现签名和验签的函数: ```python def sign(msg, d): e = int(hashlib.sha256(msg).hexdigest(), 16) k = func.random_int_range(1, N) while True: x, y = mul(k, (Gx, Gy)) r = (e + x) % N if r == 0 or k >= N: k = func.random_int_range(1, N) continue s = (cryptomath.invmod(k, N) * (d * r + k * e)) % N if s != 0: break k = func.random_int_range(1, N) return r, s def verify(msg, q, r, s): e = int(hashlib.sha256(msg).hexdigest(), 16) if r <= 0 or r >= N or s <= 0 or s >= N: return False t = (r + s) % N if t == 0: return False x, y = add(mul(s, (Gx, Gy)), mul(t, q)) if x is None or y is None: return False if (r + x) % N == e: return True else: return False ``` 最后,我们可以用以下代码来测试SM2算法的加解密: ```python d = func.random_int_range(1, N) q = mul(d, (Gx, Gy)) msg = b'Hello, world!' # 签名和验签 r, s = sign(msg, d) if verify(msg, q, r, s): print('Signature verified.') else: print('Signature verification failed.') # 加密和解密 plaintext = b'Hello, world!' k = func.random_int_range(1, N) x1, y1 = mul(k, (Gx, Gy)) c1 = hex(x1)[2:].rjust(64, '0') + hex(y1)[2:].rjust(64, '0') s = mul(N - d, add((int(c1[:64], 16), int(c1[64:], 16)), mul(k, plaintext))) c2 = hex(s[0])[2:].rjust(64, '0') + hex(s[1])[2:].rjust(64, '0') ciphertext = bytes.fromhex(c1 + c2) x2, y2 = mul(d, (int(ciphertext[:64], 16), int(ciphertext[64:128], 16))) decrypted_text = (s[1] - y2) // x2 print(decrypted_text.to_bytes((decrypted_text.bit_length() + 7) // 8, 'big')) ``` 需要注意的是,这里生成的私钥和公钥都是随机生成的,加密和解密的明文和密文都是字节串。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值