概述

本文详细介绍了如何在Java和Golang中使用SM4算法进行对称加密和解密操作。通过使用CBC模式和PKCS5填充,成功实现了跨语言的数据加密和解密。无论是Java加密后在Golang解密,还是Golang加密后在Java解密,均通过了测试验证,保证了两种语言在处理国密SM4算法时的兼容性和一致性。

前期准备

Java 国密库

 <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.70</version>
</dependency>

Golang 国密库

<!--https://github.com/Hyperledger-TWGC/ccs-gm-->
go get github.com/Hyperledger-TWGC/ccs-gm

国密SM4对称加解密

Java 加密 Golang 解密

Java 加密

/**
     * 生成SM4密钥和密文 必须使用CBC模式
     *
     * @param data 需要加密的数据
     */
    publicstaticvoidgenerateKeyAndCiphertext(byte[] data){

// 生成SM4密钥
KeyGeneratorkeyGen=null;
try{
// 生成SM4密钥
            keyGen =KeyGenerator.getInstance("SM4","BC");
            keyGen.init(128);// SM4使用128位密钥
SecretKeysecretKey= keyGen.generateKey();
byte[] key = secretKey.getEncoded();

// 生成随机的IV向量
byte[] iv =newbyte[16];
SecureRandomrandom=newSecureRandom();
            random.nextBytes(iv);
IvParameterSpecivSpec=newIvParameterSpec(iv);

// 使用SM4进行加密
Ciphercipher=Cipher.getInstance("SM4/CBC/PKCS5Padding","BC");
            cipher.init(Cipher.ENCRYPT_MODE,newSecretKeySpec(key,"SM4"), ivSpec);
byte[] encrypted = cipher.doFinal(data);

// 编码密钥、IV和密文为Base64
StringkeyBase64=Base64.toBase64String(key);
StringivBase64=Base64.toBase64String(iv);
StringencryptedBase64=Base64.toBase64String(encrypted);

// 输出Base64编码的密钥、IV和密文
System.out.println("Key (Base64): "+ keyBase64);
System.out.println("IV (Base64): "+ ivBase64);
System.out.println("Encrypted Data (Base64): "+ encryptedBase64);
}catch(Exception e){
thrownewRuntimeException(e);
}

    }

Golang 解密


/**
 *  SM4解密
 * @param keyBase64 密钥Base64编码
 * @param encryptedBase64 密文Base64编码
 */
func DecodeCiphertext(keyBase64, ivBase64, encryptedBase64 string)[]byte{
// 解码Base64编码的密钥、IV和密文
    key, err := base64.StdEncoding.DecodeString(keyBase64)
if err !=nil{
        log.Fatalf("Failed to decode key: %v", err)
}
    iv, err := base64.StdEncoding.DecodeString(ivBase64)
if err !=nil{
        log.Fatalf("Failed to decode IV: %v", err)
}
    encryptedData, err := base64.StdEncoding.DecodeString(encryptedBase64)
if err !=nil{
        log.Fatalf("Failed to decode encrypted data: %v", err)
}

// 创建SM4解密器
    block, err := sm4.NewCipher(key)
if err !=nil{
        log.Fatalf("Failed to create SM4 cipher: %v", err)
}

// 创建CBC解密模式
    mode := cipher.NewCBCDecrypter(block, iv)

// 解密数据
    decryptedData :=make([]byte,len(encryptedData))
    mode.CryptBlocks(decryptedData, encryptedData)

// 移除PKCS5填充
    decryptedData, err =RemovePKCS5Padding(decryptedData)
if err !=nil{
        log.Fatalf("Failed to remove padding: %v", err)
}

    fmt.Printf("Decrypted Data: %s\n",string(decryptedData))
return decryptedData
}

结果对比

Java

sm.generateKeyAndCiphertext("hello world".getBytes(StandardCharsets.UTF_8));
Key (Base64): 7TD7k33kyXB4d8VWK/HcDQ==
IV (Base64): x2MZrm+WXlZSSoyoqf/e6A==
Encrypted Data (Base64): GmZPfuyGYJAGWKpIQdeTpQ==

golang

func TestDecodeCiphertext(t *testing.T) {
    keyBase64 := "7TD7k33kyXB4d8VWK/HcDQ=="
    encryptedBase64 := "GmZPfuyGYJAGWKpIQdeTpQ=="
    t.Log(DecodeCiphertext(keyBase64, "x2MZrm+WXlZSSoyoqf/e6A==", encryptedBase64))
}
=== RUN   TestDecodeCiphertext
DecryptedData: hello world
    sm_test.go:25:[10410110810811132119111114108100]
--- PASS:TestDecodeCiphertext(0.00s)
PASS

Golang 加密 Java 解密

Golang 加密


/**
 *  SM4加密
 * @param data 待加密数据
 * @return keyBase64 密钥Base64编码
 */
func EncodeChainText(data []byte)(keyBase64, ivBase64, encryptedBase64 string){

// 生成SM4密钥
    key :=make([]byte,16)
if _, err := io.ReadFull(rand.Reader, key); err !=nil{
        log.Fatalf("Failed to generate key: %v", err)
}

// 生成随机的IV向量
    iv :=make([]byte,16)
if _, err := io.ReadFull(rand.Reader, iv); err !=nil{
        log.Fatalf("Failed to generate IV: %v", err)
}

// 创建SM4加密器
    block, err := sm4.NewCipher(key)
if err !=nil{
        log.Fatalf("Failed to create SM4 cipher: %v", err)
}

// 使用CBC模式加密
    mode := cipher.NewCBCEncrypter(block, iv)

// 添加PKCS5填充
    paddedData := PKCS5Padding(data, block.BlockSize())

// 加密数据
    encryptedData :=make([]byte,len(paddedData))
    mode.CryptBlocks(encryptedData, paddedData)

// 编码密钥、IV和密文为Base64
    keyBase64 = base64.StdEncoding.EncodeToString(key)
    ivBase64 = base64.StdEncoding.EncodeToString(iv)
    encryptedBase64 = base64.StdEncoding.EncodeToString(encryptedData)

// 输出Base64编码的密钥、IV和密文
    fmt.Println("Key (Base64):", keyBase64)
    fmt.Println("IV (Base64):", ivBase64)
    fmt.Println("Encrypted Data (Base64):", encryptedBase64)
return keyBase64, ivBase64, encryptedBase64
}

Java 解密

/**
     * SM4 解密
     *
     * @param keyBase64       key
     * @param ivBase64        iv
     * @param encryptedBase64 密文
     */
    publicstaticvoidDecodeCipertext(String keyBase64, String ivBase64, String encryptedBase64){

// 解码Base64编码的密钥、IV和密文
byte[] key =Base64.decode(keyBase64);
byte[] iv =Base64.decode(ivBase64);
byte[] encryptedData =Base64.decode(encryptedBase64);

// 使用SM4进行解密
Ciphercipher=null;
try{
            cipher =Cipher.getInstance("SM4/CBC/PKCS5Padding","BC");
            cipher.init(Cipher.DECRYPT_MODE,newSecretKeySpec(key,"SM4"),newIvParameterSpec(iv));
byte[] decryptedData = cipher.doFinal(encryptedData);

// 输出解密后的数据
System.out.println("Decrypted Data: "+newString(decryptedData,"UTF-8"));
}catch(Exception e){
thrownewRuntimeException(e);
}

    }

结果对比

golang


func TestEncodeChainText(t *testing.T) {
    EncodeChainText([]byte("hello go"))
}
=== RUN   TestEncodeChainText
Key (Base64): SxxgXVsnCpwak5go/wTqMg==
IV (Base64): xenl6HJR+yvvfMonpjYYug==
Encrypted Data (Base64): XgiZU0fklp+Asc0kJBfYqg==
--- PASS: TestEncodeChainText (0.00s)
PASS

java

sm.DecodeCipertext("SxxgXVsnCpwak5go/wTqMg==", "xenl6HJR+yvvfMonpjYYug==", "XgiZU0fklp+Asc0kJBfYqg==");
Decrypted Data: hello go

Process finished with exit code 0

总结

  1. 1. SM4加解密使用CBC模式,测试通过

跨语言国密SM4加解密实战:Java与Golang无缝对接的更多相关文章

  1. .NET Core加解密实战系列之——消息摘要与数字签名算法

    目录 简介 功能依赖 消息摘要算法 MD算法 家族发展史 应用场景 代码实现 MD5 示例代码 SHA算法 应用场景 代码实现 SHA1 SHA256 示例代码 MAC算法 HMAC算法的典型应用 H ...

  2. .NET Core加解密实战系列之——对称加密算法

    简介 加解密现状,编写此系列文章的背景: 需要考虑系统环境兼容性问题(Linux.Windows) 语言互通问题(如C#.Java等)(加解密本质上没有语言之分,所以原则上不存在互通性问题) 网上资料 ...

  3. .NET Core加解密实战系列之——使用BouncyCastle制作p12(.pfx)数字证书

    简介 加解密现状,编写此系列文章的背景: 需要考虑系统环境兼容性问题(Linux.Windows) 语言互通问题(如C#.Java等)(加解密本质上没有语言之分,所以原则上不存在互通性问题) 网上资料 ...

  4. 国密SM4对称算法实现说明(原SMS4无线局域网算法标准)

    国密SM4对称算法实现说明(原SMS4无线局域网算法标准) SM4分组密码算法,原名SMS4,国家密码管理局于2012年3月21日发布:http://www.oscca.gov.cn/News/201 ...

  5. 一个关于国密SM4的故事

    一个关于国密SM4的故事 我的名字叫SM4,我还有三位兄长,分别是大哥SM1, 二哥SM2, 和三哥SM3.说起我的名字,故事要回到2006年的时候,我出生的时候并不是叫SM4的,而是叫做SMS4.只 ...

  6. [转帖]一个关于国密SM4的故事

    一个关于国密SM4的故事 https://www.cnblogs.com/ouyida3/p/10053862.html SM1 硬件SM2 非对称加密SM3 hash算法SM4 对称加密 一个关于国 ...

  7. Atitit.跨语言反射api 兼容性提升与增强 java c#。Net  php  js

    Atitit.跨语言反射api 兼容性提升与增强 java c#.Net  php  js 1. 什么是反射1 1.1.       反射提供的主要功能:1 1.2.       实现反射的过程:1 ...

  8. AES加解密异常java.security.InvalidKeyException: Illegal key size

    AES加解密异常 Java后台AES解密,抛出异常如下:java.security.InvalidKeyException: Illegal key size Illegal key size or ...

  9. .NET Core加解密实战系列之——RSA非对称加密算法

    目录 简介 功能依赖 生成RSA秘钥 PKCS1格式 PKCS8格式 私钥操作 PKCS1与PKCS8格式互转 PKCS1与PKCS8私钥中提取公钥 PEM操作 PEM格式密钥读取 PEM格式密钥写入 ...

  10. openssl在多平台和多语言之间进行RSA加解密注意事项

    首先说一下平台和语言: 系统平台为CentOS6.3,RSA加解密时使用NOPADDING进行填充 1)使用C/C++调用系统自带的openssl 2)Android4.2模拟器,第三方openssl ...

随机推荐

  1. 调查报告解读之国外数据库篇:MySQL国内使用率第一,多少企业有意替换国外产品?

    为了解数据库行业以及从业人员的现状.数据库选型.中国数据库的发展趋势等,墨天轮于2022年开始进行问卷收集,历时24天,共征集到有效问卷3476份,并于2月10日整理发布了<2022年墨天轮数据 ...

  2. 2023年1月中国数据库排行榜:OceanBase 持续两月登顶,前四甲青云直上开新局

    一元复始,万象更新. 国产数据库在经历过耕获菑畲的一年后,产品.生态.人才队伍建设等都取得了重大的进展.2023年1月 墨天轮中国数据库流行度排行 火热出炉,本月排行榜"属性"列新 ...

  3. 使用datagrip时,报错 connection refused

    因为数据库没有开启 : 打开终端 输入(管理员身份): net start mysql80   (这是你的数据库的名字)

  4. Python之爬虫-全民k歌

    import re import os import requests from aip import AipSpeech from pydub import AudioSegment APP_ID ...

  5. 当多核变单核:破解CPU核心神秘失踪的终极指南!

    CPU 核心与线程识别问题解决文档 1. 背景 在一台物理主机上运行 lscpu 命令时,发现系统仅识别到 1 个核心和 1 个线程,尽管主机搭载的是 Intel Xeon E5-2686 v4 处理 ...

  6. pytest的conftest.py文件讲解

    一.conftest.py的特点 1.可以跨.py文件调用,有多个.py文件调用时,可让conftest.py只调用了一次fixture,或调用多次fixture 2.conftest.py与运行的用 ...

  7. Google Guice 与 Noear Solon 的简单对照

    1. 简介 Google Guice 是一个轻量级的依赖注入框架,它支持Java 5或者更高版本的JDK.Noear Solon 也是一个轻量级的依赖注入框架,它支持Java 8或者更高版本的JDK ...

  8. Matlab矩阵运算的硬件资源分析

    在用Matlab创建矩阵并计算矩阵乘法运算时,要注意计算机的可用内存大小(空间资源)和CPU性能(影响所用计算时间). 例如我们做以下测试:n为qubit的数目,那么一个矩阵Matrix_A=rand ...

  9. Nuxt.js 应用中的 prepare:types 事件钩子详解

    title: Nuxt.js 应用中的 prepare:types 事件钩子详解 date: 2024/11/8 updated: 2024/11/8 author: cmdragon excerpt ...

  10. 实现无感刷新Token技术:.Net Web API与axios的完美结合

    这是我之前分享在星球里面的课程,下面整理下,分享下这个无感刷新Token技术方案. 我们都知道Token是有设置有效期的,为了安全都不会设置过长的有效期:但设置有效期太短,又会导致经常需要重新登录. ...