国密加密

背景

  1. 先对内容进行签名,保证数据完整性(sm3杂凑之后再使用sm2签名)
  2. 再对内容进行加密,保证数据传输过程中的安全(sm4加解密)
  3. 再从加密内容进行解密,再签名,并于之前的签名进行比较,一致表示内容没有被修改

java实现

  1. bouncycastle 这个库已经对sm2、sm3、sm4算法进行了全面支持,所以我们也就不造轮子,直接引入到我们工程里面

  
         org.bouncycastle
         bcpkix-jdk15on
         1.57
 
  1. 对于每次操作或请求,我们不可能都随机生成一个密钥,我们要固定一个密钥,后端解析只需要拿到我们这个固定的密钥就可以去解析内容呢。
  • sm4加密密钥生成
     //产生对称秘钥
    public static byte[] generateSM4Key() throws Exception {
        KeyGenerator kg = KeyGenerator.getInstance("SM4", new BouncyCastleProvider());
        kg.init(new SecureRandom());
        return kg.generateKey().getEncoded();
    }       
  • 记住生成的byte[]数组,我使用了BASE64编码了下
    private static final String PRIVATE_KEY = "v2lBTzHwze0+SL+HtpnsGg==";
  • 初始化SM4_KEY
    private void initSM4() throws Exception {
        SM4_KEY = new SecretKeySpec(new BASE64Decoder().decodeBuffer(PRIVATE_KEY), "SM4");
        cipher = Cipher.getInstance("SM4/ECB/PKCS5Padding", new BouncyCastleProvider());
    }
  • sm4加密解密代码
    @SneakyThrows
    private byte[] softDecrypt(byte[] apiInfo) {
        cipher.init(Cipher.DECRYPT_MODE, SM4_KEY);
        return cipher.doFinal(apiInfo);
    }

    @SneakyThrows
    private byte[] softEncrypt(String apiInfo) {
        cipher.init(Cipher.ENCRYPT_MODE, SM4_KEY);
        return cipher.doFinal(apiInfo.getBytes());
    }
  • sm2密钥生成
    这个相对来说复杂点,需要自己重新计算,等我找到更好的办法后,再来更新。
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
        ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
        SecureRandom secureRandom = new SecureRandom();
        keyPairGenerator.initialize(sm2Spec, secureRandom);

        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();

        // 密钥存储
        // 私钥 D
        BigInteger D = ((BCECPrivateKey) privateKey).getD();

        // 公钥 X
        BigInteger ecPointX = ((BCECPublicKey) publicKey).getQ().getX().toBigInteger();


        // 公钥 Y
        BigInteger ecPointY = ((BCECPublicKey) publicKey).getQ().getY().toBigInteger();
  • 根据私钥D得到privateKey
        X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
        ECParameterSpec ecParameterSpec = new ECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
        ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(PRIVATE_D, ecParameterSpec);
        BCECPrivateKey privateKey = new BCECPrivateKey("EC", ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION);
        return privateKey;
  • 根据公钥X、Y得到publicKey
        X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
        ECParameterSpec ecParameterSpec = new ECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
        ECCurve curve = ecParameterSpec.getCurve();
        ECPoint point = curve.createPoint(PUBLIC_X, PUBLIC_Y);

        ECParameterSpec ecps = new ECParameterSpec(curve, ecParameterSpec.getG(), ecParameterSpec.getN());
        ECPublicKeySpec keySpec = new ECPublicKeySpec(point, ecps);

        KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
        PublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(keySpec);
        return publicKey;
  • 签名验签
    @SneakyThrows
    private boolean softVerifySign(byte[] apiInfo, byte[] signValue) {
        signature.initVerify(SIGN_PUBLIC_KEY);
        signature.update(apiInfo);
        return signature.verify(signValue);
    }

    @SneakyThrows
    private byte[] softSign(byte[] apiInfo) {
        signature.initSign(SIGN_PRIVATE_KEY);
        signature.update(apiInfo);
        return signature.sign();
    }
  • sm3杂凑
    private byte[] softSM3Digest(byte[] apiInfo) {
        byte[] md = new byte[32];
        SM3Digest sm3 = new SM3Digest();
        sm3.update(apiInfo, 0, apiInfo.length);
        sm3.doFinal(md, 0);
        return md;
    }
  • 上述只是粗糙介绍了下,等我码云代码上传或者加q交流 1660426556

你可能感兴趣的:(国密加密)