代码非常长 有六百多行
参考一位博主的理论实现
通俗易懂,十分钟读懂DES
还有很多不足的地方
感觉只是个思路
S盒(理论既定)
go
package src
// 定义S - 盒的置换表
var SBoxes = [8][4][16]int{
{
{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
{0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
},
{
{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
},
{
{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
},
{
{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
},
{
{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
{4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
},
{
{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
{9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
{4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13},
},
{
{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
{1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
{6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12},
},
{
{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
{7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
{2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11},
},
}
主代码
go
package main
import (
"bufio"
"crypto/rand"
"fmt"
"main/src"
"os"
"strings"
)
// 如果不足六十四位密钥 进行随机填充
func PadKeyWithRandom(key []byte) []byte {
// 输出原始密钥长度
fmt.Println("原始密钥长度:", len(key))
// 计算需要填充的字节数
padLen := 8 - len(key)
// 创建一个新的字节切片,长度为64位 8字节
newKey := make([]byte, 8)
// 复制原始密钥到新密钥的开头
copy(newKey, key)
// 生成随机字节填充剩余字节
randomBytes := make([]byte, padLen)
_, err := rand.Read(randomBytes)
if err != nil {
panic(err)
}
// 将随机字节添加到密钥
for i := len(key); i < 8; i++ {
newKey[i] = randomBytes[i-len(key)]
}
// 输出填充后的密钥长度
fmt.Println("填充后的密钥长度:", len(newKey))
return newKey
}
// 如果明文不足64位bit 就填充
func PadPlaintext(plaintext []byte) []byte {
for len(plaintext) < 8 {
plaintext = append(plaintext, 0x00)
}
return plaintext
}
// 初始置换 最开始
func InitialPermutation(text []byte) []byte {
if len(text) != 8 {
panic("Invalid len of 64 bits for Init")
}
var piece = [][]int{
{58, 50, 42, 34, 26, 18, 10, 2},
{60, 52, 44, 36, 28, 20, 12, 4},
{62, 54, 46, 38, 30, 22, 14, 6},
{64, 56, 48, 40, 32, 24, 16, 8},
{57, 49, 41, 33, 25, 17, 9, 1},
{59, 51, 43, 35, 27, 19, 11, 3},
{61, 53, 45, 37, 29, 21, 13, 5},
{63, 55, 47, 39, 31, 23, 15, 7},
}
result := make([]byte, 8)
for i := 0; i < len(piece); i++ {
for j := 0; j < 8; j++ {
index := piece[i][j] - 1
// 确定该比特位所在的字节在整个密钥字节切片中的某个字节索引
byteIndex := index / 8
// 在当前字节内,要处理的比特位相对于字节最高位(第 7 位)的偏移量 就是先确定某个字节再瞬移到要取的比特位
bitOffset := 7 - (index % 8)
// 分前后四字节的两段
// key[bitIndex/8]就是简单的选定要找的字节
// (1 << (7 - (bitIndex % 8)))作用是挪动1去某个位置,通过与操作来提取出原始字节中我们想要的那个比特位
// 然后开始为放入c0服务
// 将前面提取出的比特位再向右移动 7 - (bitIndex % 8) 位,这一步的目的是将提取出的比特位调整到最低位
// 最后将调整到最低位的比特位再向左移动 bitOffset 位,这样就可以将该比特位设置到 c0 中相应字节的正确位置上
result[byteIndex] |= (text[index/8] & (1 << (7 - (index % 8)))) >> (7 - (index % 8)) << bitOffset
}
}
fmt.Println(result)
return result
}
// 逆置换 最后
func ReversePermutation(text []byte) []byte {
if len(text) != 8 {
panic("Invalid len of 64 bits for Reverse")
}
var piece = [][]int{
{40, 8, 48, 16, 56, 24, 64, 32},
{39, 7, 47, 15, 55, 23, 63, 31},
{38, 6, 46, 14, 54, 22, 62, 30},
{37, 5, 45, 13, 53, 21, 61, 29},
{36, 4, 44, 12, 52, 20, 60, 28},
{35, 3, 43, 11, 51, 19, 59, 27},
{34, 2, 42, 10, 50, 18, 58, 26},
{33, 1, 41, 9, 49, 17, 57, 25},
}
result := make([]byte, 8)
for i := 0; i < len(piece); i++ {
for j := 0; j < 8; j++ {
index := piece[i][j] - 1
// 确定该比特位所在的字节在整个密钥字节切片中的某个字节索引
byteIndex := index / 8
// 在当前字节内,要处理的比特位相对于字节最高位(第 7 位)的偏移量 就是先确定某个字节再瞬移到要取的比特位
bitOffset := 7 - (index % 8)
result[byteIndex] |= (text[index/8] & (1 << (7 - (index % 8)))) >> (7 - (index % 8)) << bitOffset
}
}
return result
}
// 拆开得L0和R0
func SplitLR(text []byte) ([]byte, []byte) {
if len(text) != 8 {
panic("Invalid SplitLR of 64 bits")
}
left := text[0:4]
right := text[4:8]
return left, right
}
// 拼起来L16和R16
func MergeLR(left, right []byte) []byte {
if len(left) != 4 || len(right) != 4 {
panic("Invalid left or right for MergeLR 64 bits size")
}
text := make([]byte, 8)
copy(text[0:4], left)
copy(text[4:8], right)
return text
}
/*
// 每个加密轮应该包括扩展、生成每轮子密钥、进行异或、S盒、P盒
func Encrypt(L, R []byte) ([]byte, []byte) {
Expand32To48(R)
}
*/
// 1. 扩展32->48
func Expand32To48(input []byte) []byte {
if len(input) != 4 {
panic("Invalid len of 32bits(4 bytes) for Expand32To48")
}
// 置换表
permutationTable := [][]int{
{32, 1, 2, 3, 4, 5},
{4, 5, 6, 7, 8, 9},
{8, 9, 10, 11, 12, 13},
{12, 13, 14, 15, 16, 17},
{16, 17, 18, 19, 20, 21},
{20, 21, 22, 23, 24, 25},
{24, 25, 26, 27, 28, 29},
{28, 29, 30, 31, 32, 1},
}
result := make([]byte, 6)
var bitcount = 0 //用于统计result的比特位置
var bittarget = 0 //统计result放入的具体偏移量
for row := 0; row < len(permutationTable); row++ {
for col := 0; col < len(permutationTable[row]); col++ {
index := permutationTable[row][col] - 1
bittarget = bitcount % 8
result[bitcount/8] = input[index/8] & (1 << (7 - (index % 8))) >> (7 - (index % 8)) << bittarget
bitcount++
}
}
return result
}
// 2. 生成子密钥
// 密钥调度算法可以将64位的主密钥分成16个子密钥,每个子密钥48位,用于每轮加密中与输入数据进行异或运算。
func GenerateSubkey(key []byte) [][]byte {
// 置换选择1
C0, D0 := PC1Permutation(key)
var subkeys [][]byte
for i := 1; i <= 16; i++ {
c := CircularLeftShift(C0, i)
d := CircularLeftShift(D0, i)
subkey := PC2Permutation(c, d)
subkeys = append(subkeys, subkey)
// 详细打印当前生成的子密钥内容
fmt.Printf("生成第 %d 个 子密钥:\n", i)
fmt.Printf("子密钥内容(十六进制):")
for _, b := range subkey {
fmt.Printf("%02x ", b)
}
fmt.Println()
// 更新左移结果 一共十六轮
C0 = c
D0 = d
}
fmt.Println()
return subkeys
}
// 2.1 实现PC - 1置换操作
func PC1Permutation(key []byte) ([]byte, []byte) {
if len(key) != 8 {
panic("Invalid key length for PC1Permutation. Expected 8 bytes (64 bits).")
}
pc1Table := [][]int{
{57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18},
{10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36},
{63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22},
{14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4},
}
c0 := make([]byte, 4)
d0 := make([]byte, 4)
for i := 0; i < len(pc1Table); i++ {
for j := 0; j < len(pc1Table[i]); j++ {
// 要处理原始密钥中的第 pc表值-1 个比特位
bitIndex := pc1Table[i][j] - 1
// 确定该比特位所在的字节在整个密钥字节切片中的某个字节索引
byteIndex := bitIndex / 8
// 在当前字节内,要处理的比特位相对于字节最高位(第 7 位)的偏移量 就是先确定某个字节再瞬移到要取的比特位
bitOffset := 7 - (bitIndex % 8)
// 分前后四字节的两段
if byteIndex < 4 {
// key[bitIndex/8]就是简单的选定要找的字节
// (1 << (7 - (bitIndex % 8)))作用是挪动1去某个位置,通过与操作来提取出原始字节中我们想要的那个比特位
// 然后开始为放入c0服务
// 将前面提取出的比特位再向右移动 7 - (bitIndex % 8) 位,这一步的目的是将提取出的比特位调整到最低位
// 最后将调整到最低位的比特位再向左移动 bitOffset 位,这样就可以将该比特位设置到 c0 中相应字节的正确位置上
c0[byteIndex] |= (key[bitIndex/8] & (1 << (7 - (bitIndex % 8)))) >> (7 - (bitIndex % 8)) << bitOffset
// 输出提取后比特位在c0中的位置
//fmt.Printf("提取后比特位在c0中的位置: %d\n", byteIndex)
// 输出c0的当前状态
//fmt.Printf("c0当前状态: %v\n", c0)
} else {
// 减去 4,因为 d0 是从原始密钥经过处理后得到的后半部分 其他类同
d0[byteIndex-4] |= (key[bitIndex/8] & (1 << (7 - (bitIndex % 8)))) >> (7 - (bitIndex % 8)) << bitOffset
// 输出提取后比特位在d0中的位置
//fmt.Printf("提取后比特位在d0中的位置: %d\n", byteIndex-4)
// 输出d0的当前状态
// fmt.Printf("d0当前状态: %v\n", d0)
}
}
}
fmt.Println("c0 length:", len(c0))
fmt.Println("c0 content:", c0)
fmt.Println("d0 length:", len(d0))
fmt.Println("d0 content:", d0)
return c0, d0
}
// 循环左移操作
func CircularLeftShift(data []byte, index int) []byte {
length := len(data) * 8
var shiftAmount int
if index == 1 || index == 2 || index == 9 || index == 16 {
shiftAmount = 1
} else {
shiftAmount = 2
}
shiftBits := shiftAmount % length
if shiftBits == 0 {
return data
}
byteShift := shiftBits / 8
bitShift := shiftBits % 8
newData := make([]byte, len(data))
// 先处理整体字节的左移
for i := 0; i < len(data); i++ {
newData[i] = data[(i+byteShift)%len(data)]
}
// 处理位的左移
if bitShift > 0 {
carry := byte(0)
for i := len(newData) - 1; i >= 0; i-- {
newData[i] = (newData[i] << bitShift) | carry
carry = newData[i] >> (8 - bitShift)
}
}
return newData
}
// 2.3 PC-2置换
func PC2Permutation(c []byte, d []byte) []byte {
// totalBits := 56
// 这里totalBits应该是56,因为c0和d0都是4字节(32位),拼接起来就是56位
// fmt.Printf("totalbits:%d\n", totalBits)
// 不含奇偶校验位第 8、16、24、32、40、48、56位
pc2Table := [][]int{
{14, 17, 11, 24, 1, 5},
{3, 28, 15, 6, 21, 10},
{23, 19, 12, 4, 26, 8},
{16, 7, 27, 20, 13, 2},
{41, 52, 31, 37, 47, 55},
{30, 40, 51, 45, 33, 48},
{44, 49, 39, 56, 34, 53},
{46, 42, 50, 36, 29, 32},
}
result := make([]byte, 6)
//fmt.Println("c length:", len(c))
//fmt.Println("d length:", len(d))
//fmt.Println("combined length:", len(append(c, d...)))
// 将切片 d 中的所有元素逐个添加到切片 c 的末尾,然后返回一个新的切片
combined := append(c, d...)
fmt.Println(combined)
var bitcount = 0 //用于统计result的比特位置
var bittarget = 0 //统计result放入的具体偏移量
for i := 0; i < 8; i++ {
for j := 0; j < 6; j++ {
// 获取 表值-1 的真正的索引去cd合体的里面找
bitIndex := pc2Table[i][j] - 1
// fmt.Printf("计算出的bitIndex:%d\n", bitIndex)
// 获取字节的索引
byteIndex := bitIndex / 8
// fmt.Printf("当前pc2Table索引:[%d][%d],计算出的byteIndex:%d\n", i, j, byteIndex)
// 重新计算bitOffset,基于pc2Table的6位分组特性
//bitOffset := 7 - (bitIndex % 8)
// 根据byteIndex确定从combined中选取比特位所在的字节
byteValue := combined[byteIndex]
// 从combined特定字节bytevalue的特定比特位里取出 放入result
bittarget = bitcount % 8
result[bitcount/8] |= (byteValue & (1 << (7 - (bitIndex % 8)))) >> (7 - (bitIndex % 8)) << bittarget
bitcount++
// 记录所有子密钥的步骤在上面subkey
}
}
fmt.Println("本轮PC-2完成。")
return result
}
// 3. 异或
func xorBytes(a, b []byte) []byte {
result := make([]byte, len(a))
fmt.Println(len(a), len(b))
for i := range a {
result[i] = a[i] ^ b[i]
}
return result
}
// 4. S盒
func Sbox48To32(input []byte) []byte {
if len(input) != 6 {
panic("Invalid input length for SBox48To32. Expected 6 bytes (48 bits).")
}
// 将输入的字节切片转换为uint64类型
var inputUint64 uint64
for i, b := range input {
inputUint64 |= uint64(b) << (uint64(i) * 8)
}
output := make([]byte, 4) // 4 bytes output for 32 bits
var out uint32 = 0
println("S盒循环中......")
// 遍历 8 个 6 位数据块
for i := 0; i < 8; i++ {
// 提取当前6位数据块
// 0x3f 在二进制下是 00111111。
// 与这个值进行与操作, 只保留最低 6 位,
// 从而准确提取出当前要处理的 6 位数据块,并存到 b 中。
b := (uint8)(inputUint64>>(uint64(i)*6)) & 0x3f
// 计算行索引:第1位和第6位
r := (b&1)<<1 + (b >> 5)
// 计算列索引:第2到第5位
c := ((b>>1)&1)<<3 + ((b>>2)&1)<<2 + ((b>>3)&1)<<1 + ((b >> 4) & 1)
o := src.SBoxes[i][r][c]
// 由于查表是小端模式,需要转换至大端
var o2 uint8 = 0
for j := 0; j < 4; j++ {
o2 |= uint8((o>>j)&1) << (uint8(3 - j))
}
out |= uint32(o2) << (i * 4)
}
// 将处理后的结果填充到输出切片
for i := 0; i < 4; i++ {
output[i] = byte((out >> (i * 8)) & 0xff)
}
return output
}
// 5. P盒
func PboxExchange(input []byte) []byte {
Pbox := [][]int{
{16, 7, 20, 21},
{29, 12, 28, 17},
{1, 15, 23, 26},
{5, 18, 31, 10},
{2, 8, 24, 14},
{32, 27, 3, 9},
{19, 13, 30, 6},
{22, 11, 4, 25},
}
if len(input) != 4 {
panic("Invalid input length for PboxExchange. Expected 4 bytes(32bits).")
}
// 将输入的字节切片转换为uint32类型
var inputUint32 uint32
for i, b := range input {
inputUint32 |= uint32(b) << (uint32(i) * 8)
}
var out uint32 = 0
for i := 0; i < 4; i++ {
for j := 0; j < 4; j++ {
index := Pbox[i][j] - 1
// 确保index在有效范围内(0到3)
if index < 0 {
index = 0
} else if index >= len(input) {
index = len(input) - 1
}
out |= (inputUint32 >> (uint32(index) * 8)) & 0xff << (uint32(i*4+j) * 8)
}
}
// 将置换后的结果转换为字节切片返回
output := make([]byte, 4)
for i := 0; i < 4; i++ {
output[i] = byte((out >> (i * 8)) & 0xff)
}
fmt.Println(output)
return output
}
// 解密函数,执行与加密相反的操作流程
func Decrypt(ciphertext []byte, subkeys [][]byte) []byte {
fmt.Println("开始解密......")
// 用于存储每组解密后的结果
// 转换成字节切片组,8个字节一组
var cipherGroups [][]byte
for i := 0; i < len(ciphertext); i += 8 {
endIndex := i + 8
if endIndex > len(ciphertext) {
endIndex = len(ciphertext)
}
cipherGroups = append(cipherGroups, []byte(ciphertext[i:endIndex]))
}
// 用于存储每组解密后的结果
var decryptedGroups [][]byte
for _, group := range cipherGroups {
println("开始初始置换")
// 3. 初始置换
paddedGroup := PadPlaintext(group)
permutedText := InitialPermutation(paddedGroup)
println("初始置换完毕")
// 4. 拆分L0和R0
//println("开始拆分L0和R0")
L, R := SplitLR(permutedText)
println("拆分L0和R0完毕")
// 5. 进行16轮加密
for i := 0; i < 16; i++ {
// 扩展R
expandedR := Expand32To48(R)
//println("扩展完毕")
// 生成子密钥
subkey := subkeys[15-i]
// 异或
xored := xorBytes(expandedR, subkey)
//println("异或完毕")
fmt.Printf("异或结果:%v\n", xored)
// S盒变换
sboxed := Sbox48To32(xored)
//println("S盒完毕")
// P盒变换
pboxed := PboxExchange(sboxed)
//println("P盒完毕")
// 与L异或
newL := xorBytes(L, pboxed)
//println("二次异或完毕")
L = R
R = newL
}
// 6. 合并L16和R16
plaintext := MergeLR(L, R)
// 7. 逆置换
finalCiphertext := ReversePermutation(plaintext)
decryptedGroups = append(decryptedGroups, finalCiphertext)
}
// 将所有组的解密结果组合起来
finalDecryptedText := []byte{}
for _, decryptedGroup := range decryptedGroups {
finalDecryptedText = append(finalDecryptedText, decryptedGroup...)
}
return finalDecryptedText
}
func main() {
println("请输入明文:")
reader := bufio.NewReader(os.Stdin)
plaintextStr, err := reader.ReadString('\n')
if err != nil {
fmt.Println("读取输入时出错:", err)
return
}
// 去除字符串末尾的换行符
plaintextStr = strings.TrimSpace(plaintextStr)
// 转换成字节切片组,8个字节一组
var plainGroups [][]byte
for i := 0; i < len(plaintextStr); i += 8 {
endIndex := i + 8
if endIndex > len(plaintextStr) {
endIndex = len(plaintextStr)
}
plainGroups = append(plainGroups, []byte(plaintextStr[i:endIndex]))
}
// 假设主密钥为8字节(64位)
println("请输入密钥:")
reader = bufio.NewReader(os.Stdin)
keyyy, err := reader.ReadString('\n')
if err != nil {
fmt.Println("读取输入时出错:", err)
return
}
// 去除字符串末尾的换行符
keyStr := strings.TrimSpace(keyyy)
key := []byte(keyStr)
//key := []byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}
println("开始填充密钥")
// 1. 填充密钥(如果需要)
newKey := PadKeyWithRandom(key)
//println("填充结果:", newKey)
println("填充结果:")
for _, b := range newKey {
fmt.Printf("%02x ", b)
}
println("开始生成子密钥")
// 2. 生成子密钥
subkeys := GenerateSubkey(newKey)
// 用于存储每组加密后的结果
var encryptedGroups [][]byte
fmt.Printf("明文字节组数:%d\n", len(plainGroups))
for _, group := range plainGroups {
println("开始初始置换")
// 3. 初始置换
paddedGroup := PadPlaintext(group)
permutedText := InitialPermutation(paddedGroup)
println("初始置换完毕")
// 4. 拆分L0和R0
//println("开始拆分L0和R0")
L, R := SplitLR(permutedText)
println("拆分L0和R0完毕")
// 5. 进行16轮加密
for i := 0; i < 16; i++ {
// 扩展R
expandedR := Expand32To48(R)
//println("扩展完毕")
// 生成子密钥
subkey := subkeys[i]
// 异或
xored := xorBytes(expandedR, subkey)
//println("异或完毕")
fmt.Printf("异或结果:%v\n", xored)
// S盒变换
sboxed := Sbox48To32(xored)
//println("S盒完毕")
// P盒变换
pboxed := PboxExchange(sboxed)
//println("P盒完毕")
// 与L异或
newL := xorBytes(L, pboxed)
//println("二次异或完毕")
L = R
R = newL
}
// 6. 合并L16和R16
ciphertext := MergeLR(L, R)
// 7. 逆置换
finalCiphertext := ReversePermutation(ciphertext)
encryptedGroups = append(encryptedGroups, finalCiphertext)
}
// 将所有组的加密结果组合起来
finalEncryptedText := []byte{}
for _, encryptedGroup := range encryptedGroups {
finalEncryptedText = append(finalEncryptedText, encryptedGroup...)
}
// 调用解密函数进行解密验证
decryptedText := Decrypt(finalEncryptedText, subkeys)
fmt.Printf("明文解析字节内容:%x\n", plainGroups)
fmt.Printf("加密后的密文: %x\n", finalEncryptedText)
fmt.Printf("解密后的明文: %x\n", decryptedText)
}