首页 > 编程语言 >跨语言国密SM4加解密实战:Java与Golang无缝对接

跨语言国密SM4加解密实战:Java与Golang无缝对接

时间:2024-12-02 15:44:22浏览次数:8  
标签:keyBase64 Base64 Java err SM4 加解密 key byte

概述

本文详细介绍了如何在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模式,测试通过

标签:keyBase64,Base64,Java,err,SM4,加解密,key,byte
From: https://www.cnblogs.com/exmyth/p/18581992

相关文章

  • 突击检查:Java面试之多线程&并发篇(10)
    前言本来想着给自己放松一下,刷刷博客,突然被几道面试题难倒!说说CyclicBarrier和CountDownLatch的区别?什么是AQS?了解Semaphore吗?什么是Callable和Future?什么是阻塞队列?阻塞队列的实现原理是什么?如何使用阻塞队列来实现生产者-消费者模型?似乎有点模糊了,那就大概看一下面试题吧。好记......
  • JavaScript操作DOM元素的classList
    在JavaScript中,classList是一个DOM元素属性,它提供了一组方法来添加、移除和切换元素的类名。classList属性返回一个DOMTokenList集合,表示元素的类名。这个集合提供了几个非常有用的方法,我们可以方便地对元素的类名进行操作,包括添加、移除、切换类名等。1,添加类名add(class1......
  • P1746 离开中山路 JAVA题解 (广搜和双向广搜优化)
    题目背景《爱与愁的故事第三弹·shopping》最终章。题目描述爱与愁大神买完东西后,打算坐车离开中山路。现在爱与愁大神在 x1,y1x1​,y1​ 处,车站在 x2,y2x2​,y2​ 处。现在给出一个 n×n(n≤1000)n×n(n≤1000) 的地图,00 表示马路,11 表示店铺(不能从店铺穿过),爱与愁......
  • 1100 道 Java 面试题(含答案)
    2025年马上快到了,发现网上很多Java面试题都没有答案,所以花了很长时间搜集整理出来了这套Java面试题大全~这套互联网Java工程师面试题包括了:MyBatis、ZK、Dubbo、EL、Redis、MySQL、并发编程、Java面试、Spring、微服务、Linux、Springboot、SpringCloud、MQ、Kafka面试专题......
  • 基于Java+SpringBoot+Vue的前后端分离的口腔管家平台
    基于Java+SpringBoot+Vue的前后端分离的口腔管家平台前言✌全网粉丝20W+,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌......
  • 基于Java+SpringBoot+Vue的前后端分离的垃圾分类网站
    基于Java+SpringBoot+Vue的前后端分离的垃圾分类网站前言✌全网粉丝20W+,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌......
  • Java中的类变量
    在Java中,类变量是指使用static修饰的变量。它是属于类本身的,而不是某个对象的,因此所有类的实例共享同一个类变量。类变量的特点属于类本身类变量在内存中只存在一份,所有该类的实例共享同一个变量。声明方式使用static关键字声明。生命周期类变量在类加载时被初......
  • Java中的静态方法
    在Java中,静态方法是使用static关键字修饰的方法。它属于类本身,而不是类的实例。静态方法可以在不创建类的对象的情况下直接调用,因此常用于工具类、工厂方法或全局逻辑的实现。静态方法的特点属于类本身静态方法是类级别的,直接与类相关,而不是与某个实例相关。不依赖于实......
  • 基于Java的电子产品租借管理系统的设计与实现-毕业设计源码39512
    基于Java的电子产品租借管理系统的设计与实现摘 要信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对电子产品租借管理系统的设计与实现等问题,对电......
  • 基于Java web的考勤系统设计与实现-计算机毕业设计源码42117
    基于Javaweb的考勤系统设计与实现摘 要随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,考勤系统的研究旨在设计和开发一种自动化的考勤管理系统,以提高组织内部的考勤效率、减少人力成本,并确保员工的出勤数据......