保护数据隐私:深入探索Golang中的SM4加密解密算法

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 保护数据隐私:深入探索Golang中的SM4加密解密算法

前言

最近做的项目对安全性要求比较高,特别强调:系统不能涉及MD5、SHA1、RSA1024、DES高风险算法。

image.png

那用什么嘞?甲方:建议用国产密码算法SM4。

擅长敏捷开发(CV大法)的我,先去GitHub找了开源项目、又去网络上找了一些教程,但是或多或少都有些问题:

  1. 比如golang.org/x/crypto/sm4无法安装编译
  2. 比如C站烂大街的SM4教程,不能解决数据填充的问题,超过16位就解密失败了
  3. 比如如何封装成通用的方法,供系统进行调用
  4. 更多就是复制粘贴了SM4的定义,很抽象。

于是我花了2天时间研究SM4的原理和应用,解决了上面这些问题,整理这篇文章分享给大家,让大家能少踩坑。

我会按照下面的顺序分享这篇文章,方便大家更好的理解,如果你就是喜欢拿来主义(敏捷开发),可以直接copy底部的示例代码,快速上手使用即可。

文章目录

  1. SM4的优势
  2. IV是什么?
  3. SM4加密的方式和原理
  4. SM4的各种工作模式对比
  5. 直接可用的「代码示例」
  6. 核心方法的源码解析
  7. 总结回顾

1. SM4的优势

相比于其他加密算法,SM4加密算法具有以下几个优势:

  1. 高安全性:SM4是一种对称加密算法,采用128位密钥长度,具有较高的安全性和抗攻击性。它经过了广泛的安全性分析和评估,并通过了多个密码学标准的验证。
  2. 高效性:SM4算法的加密和解密速度较快,适用于对大量数据进行加密和解密的场景。它在硬件和软件实现上都具有高效性能。
  3. 简单性:SM4算法的实现相对简单,代码量较小,易于理解和使用。它的设计目标之一是提供一种易于实现和部署的加密算法。
  4. 标准化SM4算法是中国国家密码管理局发布的密码算法标准,得到了广泛的应用和认可。它已成为国际上公认的密码算法之一。
  5. 广泛支持:SM4算法在各种平台和编程语言中都有支持和实现,包括Go、Java、C/C++等。它可以在不同的系统和环境中进行跨平台的应用和部署。
  6. 可扩展性:SM4算法支持不同的工作模式和填充方式,可以根据具体需求进行灵活配置。它可以与其他密码算法结合使用,提供更高级别的安全保护。

小小的总结一下:SM4加密算法在安全性、高效性、简单性、标准化和广泛支持等方面具有优势,适用于各种数据保护和加密应用场景。它是一种可靠的加密算法选择。

2.IV是什么?

我在学习的时候看到IV就蒙了,所以有必要先说清楚IV的概念:

Initialization Vector(IV)是一种在密码学中使用的初始值。它是一个固定长度的随机数或者随机生成的值,用于在加密算法中初始化密码算法的状态。

在加密过程中,IV的作用是引入随机性和唯一性,以增加加密的安全性。 它与密钥一起用于初始化密码算法的内部状态,确保每次加密操作都产生不同的输出,即使相同的明文使用相同的密钥进行加密。

IV的长度和使用方式取决于具体的加密算法和应用场景。在使用加密算法时,IV通常需要与密文一起传输给解密方,以便解密方能够正确还原明文。

需要注意的是:IV本身不需要保密,可以与密文一起传输。然而,为了确保加密的安全性,IV应该是随机生成的,并且每次加密操作都应该使用不同的IV。这样可以防止密码分析者通过观察加密结果的模式来破解密钥或者明文。

3. SM4加密的方式和原理

SM4加密算法是一种对称加密算法,采用分组密码的方式对数据进行加密。

下面是SM4加密的方式和原理的简要说明:

  1. 密钥扩展:SM4使用128位的密钥,首先对密钥进行扩展,生成32个子密钥,用于后续的加密轮操作。
  2. 初始轮:将明文分为4个字节的分组,与第一个子密钥进行异或操作。
  3. 加密轮:SM4加密算法共进行32轮加密操作。每轮操作包括以下步骤:
  • 字节替换:使用S盒进行字节替换。
  • 行移位:对每个分组进行行移位操作。
  • 列混淆:对每个分组进行列混淆操作。
  • 轮密钥加:将当前轮的子密钥与分组进行异或操作。
  1. 最终轮:在最后一轮加密操作中,不进行列混淆操作,只进行字节替换、行移位和轮密钥加操作。
  2. 输出:经过32轮加密操作后,得到加密后的密文。

SM4加密算法的安全性和强度主要来自于其复杂的轮函数和密钥扩展过程。它具有较高的安全性和抗攻击性,并且在实际应用中得到了广泛的应用和认可。

需要注意的是:SM4加密算法的安全性还依赖于密钥的保密性和随机性。在使用SM4进行加密时,应确保使用足够强度的密钥,并采取适当的密钥管理和保护措施。

4.SM4的各种工作模式对比

SM4加密算法可以使用不同的工作模式,其中包括CBC(Cipher Block Chaining)模式。

我使用的是CBC模式,下面和大家分享一下CBC模式与其他模式的对比:

  1. CBC模式(Cipher Block Chaining):
  • 特点:每个明文块与前一个密文块进行异或操作,然后再进行加密。初始块使用初始化向量(IV)。
  • 优点:具有较好的安全性,能够隐藏明文的模式和重复性。
  • 缺点:加密过程是串行的,不适合并行处理。
  1. ECB模式(Electronic Codebook):
  • 特点:将每个明文块独立加密,相同的明文块会得到相同的密文块。
  • 优点:简单、并行处理效率高。
  • 缺点:不能隐藏明文的模式和重复性,不适合加密大量重复的数据。
  1. CFB模式(Cipher Feedback):
  • 特点:将前一个密文块作为输入来加密当前的明文块,可以实现流密码的功能。
  • 优点:能够处理不定长的数据流,适用于实时加密和流式传输。
  • 缺点:加密过程是串行的,不适合并行处理。
  1. OFB模式(Output Feedback):
  • 特点:将前一个密文块作为输入来生成密钥流,然后与明文块进行异或操作,可以实现流密码的功能。
  • 优点:能够处理不定长的数据流,适用于实时加密和流式传输。
  • 缺点:加密过程是串行的,不适合并行处理。
  1. CTR模式(Counter):
  • 特点:使用一个计数器来生成密钥流,然后与明文块进行异或操作,可以实现流密码的功能。
  • 优点:能够处理不定长的数据流,适用于实时加密和流式传输。并行处理效率高,适合硬件实现。
  • 缺点:需要保证计数器的唯一性,否则会导致密钥流的重复。

对比总结:

  • CBC模式和ECB模式相比,CBC模式具有更好的安全性,能够隐藏明文的模式和重复性,而ECB模式无法隐藏这些信息。
  • CFB模式、OFB模式和CTR模式都是流密码模式,适用于不定长的数据流加密,能够实现实时加密和流式传输。它们的主要区别在于密钥流的生成方式和加密过程的并行性。
  • CFB模式和OFB模式的加密过程是串行的,不适合并行处理,而CTR模式的加密过程可以并行处理,适合硬件实现。

总的来说:CBC模式在安全性方面较好,能够隐藏明文的模式和重复性。而流密码模式(CFB、OFB和CTR)适用于不定长数据流的加密,能够实现实时加密和流式传输,其中CTR模式具有较好的并行处理性能。选择合适的加密模式取决于具体的应用需求和安全性要求。

5. 直接可用的「代码示例」

我一直认为可以通过复制粘贴,直接跑通的示例代码才是好代码。

没错,我的代码示例就是这样,并且关键代码都写好了注释:

package main
import (
  "bytes"
  "crypto/cipher"
  "encoding/hex"
  "fmt"
  "github.com/tjfoc/gmsm/sm4"
)
// SM4加密
func SM4Encrypt(data string) (result string, err error) {
  //字符串转byte切片
  plainText := []byte(data)
  //建议从配置文件中读取秘钥,进行统一管理
  SM4Key := "Uv6tkf2M3xYSRuFv"
  //todo 注意:iv需要是随机的,进一步保证加密的安全性,将iv的值和加密后的数据一起返回给外部
  SM4Iv := "04TzMuvkHm_EZnHm"
  iv := []byte(SM4Iv)
  key := []byte(SM4Key)
  //实例化sm4加密对象
  block, err := sm4.NewCipher(key)
  if err != nil {
    panic(err)
  }
  //明文数据填充
  paddingData := paddingLastGroup(plainText, block.BlockSize())
  //声明SM4的加密工作模式
  blockMode := cipher.NewCBCEncrypter(block, iv)
  //为填充后的数据进行加密处理
  cipherText := make([]byte, len(paddingData))
  //使用CryptBlocks这个核心方法,将paddingData进行加密处理,将加密处理后的值赋值到cipherText中
  blockMode.CryptBlocks(cipherText, paddingData)
  //加密结果使用hex转成字符串,方便外部调用
  cipherString := hex.EncodeToString(cipherText)
  return cipherString, nil
}
// SM4解密 传入string 输出string
func SM4Decrypt(data string) (res string, err error) {
  //秘钥
  SM4Key := "Uv6tkf2M3xYSRuFv"
  //iv是Initialization Vector,初始向量,
  SM4Iv := "04TzMuvkHm_EZnHm"
  iv := []byte(SM4Iv)
  key := []byte(SM4Key)
  block, err := sm4.NewCipher(key)
  if err != nil {
    panic(err)
  }
  //使用hex解码
  decodeString, err := hex.DecodeString(data)
  if err != nil {
    return "", err
  }
  //CBC模式 优点:具有较好的安全性,能够隐藏明文的模式和重复性。 缺点:加密过程是串行的,不适合并行处理。
  blockMode := cipher.NewCBCDecrypter(block, iv)
  //下文有详解这段代码的含义
  blockMode.CryptBlocks(decodeString, decodeString)
  //去掉明文后面的填充数据
  plainText := unPaddingLastGroup(decodeString)
  //直接返回字符串类型,方便外部调用
  return string(plainText), nil
}
// 明文数据填充
func paddingLastGroup(plainText []byte, blockSize int) []byte {
  //1.计算最后一个分组中明文后需要填充的字节数
  padNum := blockSize - len(plainText)%blockSize
  //2.将字节数转换为byte类型
  char := []byte{byte(padNum)}
  //3.创建切片并初始化
  newPlain := bytes.Repeat(char, padNum)
  //4.将填充数据追加到原始数据后
  newText := append(plainText, newPlain...)
  return newText
}
// 去掉明文后面的填充数据
func unPaddingLastGroup(plainText []byte) []byte {
  //1.拿到切片中的最后一个字节
  length := len(plainText)
  lastChar := plainText[length-1]
  //2.将最后一个数据转换为整数
  number := int(lastChar)
  return plainText[:length-number]
}
func main() {
  //待加密的数据 模拟18位的身份证号
  plainText := "131229199907097219"
  //SM4加密
  decrypt, err := SM4Encrypt(plainText)
  if err != nil {
    return
  }
  fmt.Printf("sm4加密结果:%s\n", decrypt)
  //cipherString := hex.EncodeToString(cipherText)
  //fmt.Printf("sm4加密结果转成字符串:%s\n", cipherString)
  //SM4解密
  sm4Decrypt, err := SM4Decrypt(decrypt)
  if err != nil {
    return
  }
  fmt.Printf("plainText:%s\n", sm4Decrypt)
  flag := plainText == sm4Decrypt
  fmt.Println("解密是否成功:", flag)
}

运行结果如下:

image.png

6. 核心方法的源码解析

细心的小伙伴应该又发现,(或者通过你真实的敲代码一定能发现。

在加密和解密部分有一个CryptBlocks()方法,我们来解析一下这段源码:

  // CryptBlocks encrypts or decrypts a number of blocks. The length of
  // src must be a multiple of the block size. Dst and src must overlap
  // entirely or not at all.
  //
  // If len(dst) < len(src), CryptBlocks should panic. It is acceptable
  // to pass a dst bigger than src, and in that case, CryptBlocks will
  // only update dst[:len(src)] and will not touch the rest of dst.
  //
  // Multiple calls to CryptBlocks behave as if the concatenation of
  // the src buffers was passed in a single run. That is, BlockMode
  // maintains state and does not reset at each CryptBlocks call.
  CryptBlocks(dst, src []byte)

翻译翻译

CryptBlocks方法用于加密或解密多个数据块。src的长度必须是块大小的倍数。dst和src必须完全重叠或完全不重叠。

如果len(dst) < len(src),CryptBlocks方法应该引发panic。允许传递比src更大的dst,此时CryptBlocks只会更新dst[:len(src)],不会触及dst的其余部分。

在这段代码注释中,dst表示目标缓冲区,用于存储加密或解密后的结果。src表示源缓冲区,包含要加密或解密的数据。这两个缓冲区可以是相同的内存区域,也可以是不同的内存区域。CryptBlocks方法会将src中的数据进行加密或解密,并将结果存储在dst中。

需要注意的是,dst和src的长度必须是块大小的倍数,否则CryptBlocks方法可能会引发panic。如果dst的长度小于src的长度,CryptBlocks方法只会更新dst的前len(src)个字节,并不会修改dst的其余部分。

此外,CryptBlocks方法可以多次调用,多次调用的效果相当于将所有src缓冲区的数据连接在一起,然后进行加密或解密。这意味着BlockMode会保持状态,并且不会在每次CryptBlocks调用时重置。

如果你看注释翻译理解起来还是比较抽象的话,我换个方式介绍一下:

用我的话来说

在SM4加密中,CryptBlocks()方法是用于加密或解密多个数据块的方法。它是SM4算法中的一个核心函数。

具体来说,CryptBlocks()方法接受一个源数据缓冲区(src)和一个目标数据缓冲区(dst),并对源数据进行加密或解密操作,将结果存储在目标数据缓冲区中。

在加密过程中,CryptBlocks()方法会将源数据分成多个数据块,然后对每个数据块进行加密操作,并将结果存储在目标数据缓冲区中。加密过程中使用的密钥和其他参数由SM4算法的实现确定。

在解密过程中,CryptBlocks()方法会对源数据缓冲区中的数据块进行解密操作,并将解密后的结果存储在目标数据缓冲区中。

需要注意的是:CryptBlocks()方法要求源数据缓冲区和目标数据缓冲区的长度必须是SM4算法的块大小的倍数。否则,可能会引发错误或产生不可预测的结果。

CryptBlocks()方法是SM4加密算法中用于加密或解密多个数据块的关键方法,它实现了SM4算法的核心功能。

7. 总结回顾

我之前也写过一篇解密解密的文章,欢迎大家阅读指教:保障网络请求数据传输的安全性、一致性和防篡改:对称加密与非对称加密的结合

相信你读了这篇文章能对SM4加密有个整体理解,通过我在文章中提供的示例代码可以快速跑通加密和解密流程。我还带着你分析了CryptBlocks()源码的作用。


相关文章
|
1月前
|
存储 SQL 安全
加密后的数据如何进行模糊查询?
在数据安全和隐私保护日益重要的今天,加密技术成为保护敏感数据的重要手段。然而,加密后的数据在存储和传输过程中虽然安全性得到了提升,但如何对这些数据进行高效查询,尤其是模糊查询,成为了一个挑战。本文将深入探讨如何在保证数据安全的前提下,实现加密数据的模糊查询功能。
212 0
|
1月前
|
安全 网络安全 区块链
网络安全与信息安全:构建数字世界的防线在当今数字化时代,网络安全已成为维护个人隐私、企业机密和国家安全的重要屏障。随着网络攻击手段的不断升级,从社交工程到先进的持续性威胁(APT),我们必须采取更加严密的防护措施。本文将深入探讨网络安全漏洞的形成原因、加密技术的应用以及提高公众安全意识的重要性,旨在为读者提供一个全面的网络安全知识框架。
在这个数字信息日益膨胀的时代,网络安全问题成为了每一个网民不可忽视的重大议题。从个人信息泄露到企业数据被盗,再到国家安全受到威胁,网络安全漏洞如同隐藏在暗处的“黑洞”,时刻准备吞噬掉我们的信息安全。而加密技术作为守护网络安全的重要工具之一,其重要性不言而喻。同时,提高公众的安全意识,也是防范网络风险的关键所在。本文将从网络安全漏洞的定义及成因出发,解析当前主流的加密技术,并强调提升安全意识的必要性,为读者提供一份详尽的网络安全指南。
|
2月前
|
安全 算法 网络安全
网络安全与信息安全:构建数字世界的坚固防线在数字化浪潮席卷全球的今天,网络安全与信息安全已成为维系社会秩序、保障个人隐私和企业机密的关键防线。本文旨在深入探讨网络安全漏洞的本质、加密技术的前沿进展以及提升公众安全意识的重要性,通过一系列生动的案例和实用的建议,为读者揭示如何在日益复杂的网络环境中保护自己的数字资产。
本文聚焦于网络安全与信息安全领域的核心议题,包括网络安全漏洞的识别与防御、加密技术的应用与发展,以及公众安全意识的培养策略。通过分析近年来典型的网络安全事件,文章揭示了漏洞产生的深层原因,阐述了加密技术如何作为守护数据安全的利器,并强调了提高全社会网络安全素养的紧迫性。旨在为读者提供一套全面而实用的网络安全知识体系,助力构建更加安全的数字生活环境。
|
1月前
|
安全 算法 网络安全
网络安全与信息安全:守护数字世界的坚盾在这个高度数字化的时代,网络安全和信息安全已成为全球关注的焦点。无论是个人隐私还是企业数据,都面临着前所未有的风险和挑战。本文将深入探讨网络安全漏洞、加密技术以及安全意识的重要性,旨在为读者提供实用的知识,帮助构建更加安全的网络环境。
【10月更文挑战第4天】 在数字化浪潮中,网络安全与信息安全成为不可忽视的议题。本文通过分析网络安全漏洞的类型与成因,探讨加密技术的原理与应用,并强调提升安全意识的必要性,为读者提供一套全面的网络安全知识框架。旨在帮助个人和企业更好地应对网络威胁,保护数字资产安全。
114 65
|
15天前
|
数据库 数据安全/隐私保护 Windows
Windows远程桌面出现CredSSP加密数据修正问题解决方案
【10月更文挑战第30天】本文介绍了两种解决Windows系统凭据分配问题的方法。方案一是通过组策略编辑器(gpedit.msc)启用“加密数据库修正”并将其保护级别设为“易受攻击”。方案二是通过注册表编辑器(regedit)在指定路径下创建或修改名为“AllowEncryptionOracle”的DWORD值,并将其数值设为2。
43 3
|
21天前
|
安全 网络安全 数据安全/隐私保护
网络安全与信息安全:从漏洞到加密,保护数据的关键步骤
【10月更文挑战第24天】在数字化时代,网络安全和信息安全是维护个人隐私和企业资产的前线防线。本文将探讨网络安全中的常见漏洞、加密技术的重要性以及如何通过提高安全意识来防范潜在的网络威胁。我们将深入理解网络安全的基本概念,学习如何识别和应对安全威胁,并掌握保护信息不被非法访问的策略。无论你是IT专业人士还是日常互联网用户,这篇文章都将为你提供宝贵的知识和技能,帮助你在网络世界中更安全地航行。
|
1月前
|
算法 安全 数据安全/隐私保护
加密和解密数据
【10月更文挑战第6天】加密和解密数据
48 2
|
19天前
|
算法 安全 物联网
关于SM2、SM3、SM4、SM9这四种国密算法
本文介绍了四种国密算法——SM2、SM3、SM4和SM9。SM2是一种基于椭圆曲线的非对称加密算法,用于数据加密和数字签名;SM3是哈希算法,用于数字签名和消息完整性验证;SM4是对称加密算法,用于数据加密和解密;SM9是基于标识的非对称密码算法,适用于物联网环境中的数据安全和隐私保护。
123 0
|
1月前
|
SQL 安全 算法
网络安全与信息安全:构建数字世界的防线在数字化浪潮席卷全球的今天,网络安全与信息安全已成为维系社会秩序、保障个人隐私与企业机密的重要基石。本文旨在深入探讨网络安全漏洞的本质、加密技术的前沿进展以及提升安全意识的有效策略,为读者揭示数字时代下信息保护的核心要义。
本文聚焦网络安全与信息安全领域,详细剖析了网络安全漏洞的形成机理、常见类型及其潜在危害,强调了及时检测与修复的重要性。同时,文章系统介绍了对称加密、非对称加密及哈希算法等主流加密技术的原理、应用场景及优缺点,展现了加密技术在保障数据安全中的核心地位。此外,针对社会普遍存在的安全意识薄弱问题,提出了一系列切实可行的提升措施,如定期安全培训、强化密码管理、警惕钓鱼攻击等,旨在引导公众树立全面的网络安全观,共同构筑数字世界的安全防线。
|
1月前
|
数据安全/隐私保护
sm4加密工具类
sm4加密工具类
24 3