• Go语言中如何使用AES算法对字符串和文件进行加解密?
  • 发布于 2个月前
  • 166 热度
    0 评论
AES 密码与分组密码 Rijndael 基本上完全一致,Rijndael 分组大小和密钥大小都可以为 128 位、192 位和256 位。然而 AES 只要求分组大小为 128 位,因此只有分组长度为 128Bit 的 Rijndael 才称为 AES 算法。但这并不妨碍三种密码的相同使用环境。

1 对字符串加解密
package main

import (
    "bytes"
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "errors"
    "fmt"
)

// 测试一下
func main() {
    data: = "aes 加密测试!"
        // 加密
    enstr,
    _: = EncryptByAes([] byte(data))
        // 解密
    destr,
    _: = DecryptByAes(enstr)
        // 打印
    fmt.Printf(" 加密:%v\n 解密:%s", enstr, destr)
}

var PwdKey = [] byte("ABCDABCDABCDABCD") // 三种密码标准:128 位、192 位和 256 位,对应字符串位数 16、32、64
    // EncryptByAes Aes加密 后 base64 再加
func EncryptByAes(data[] byte)(string, error) {
    res, err: = AesEncrypt(data, PwdKey)
    if err != nil {
        return "", err
    }
    return base64.StdEncoding.EncodeToString(res), nil
}
// 堆代码 duidaima.com
// DecryptByAes Aes 解密
func DecryptByAes(data string)([] byte, error) {
    dataByte, err: = base64.StdEncoding.DecodeString(data)
    if err != nil {
        return nil, err
    }
    return AesDecrypt(dataByte, PwdKey)
}

// 加密
func AesEncrypt(data[] byte, key[] byte)([] byte, error) {
    // 创建加密实例
    block, err: = aes.NewCipher(key)
    if err != nil {
            return nil, err
        }
        // 判断加密快的大小
    blockSize: = block.BlockSize()
        // 填充
    encryptBytes: = pkcs7Padding(data, blockSize)
        // 初始化加密数据接收切片
    crypted: = make([] byte, len(encryptBytes))
        // 使用cbc加密模式
    blockMode: = cipher.NewCBCEncrypter(block, key[: blockSize]) // Cipher Block Chaining:加密块链
        // 执行加密
    blockMode.CryptBlocks(crypted, encryptBytes)
    return crypted, nil
}

// 解密
func AesDecrypt(data[] byte, key[] byte)([] byte, error) {
    // 创建实例
    block, err: = aes.NewCipher(key)
    if err != nil {
            return nil, err
        }
        // 获取块的大小
    blockSize: = block.BlockSize()
        // 使用cbc
    blockMode: = cipher.NewCBCDecrypter(block, key[: blockSize]) // Cipher Block Chaining:加密块链
        // 初始化解密数据接收切片
    crypted: = make([] byte, len(data))
        // 执行解密
    blockMode.CryptBlocks(crypted, data)
        // 去除填充
    crypted, err = pkcs7UnPadding(crypted)
    if err != nil {
        return nil, err
    }
    return crypted, nil
}

// pkcs7Padding 填充
func pkcs7Padding(data[] byte, blockSize int)[] byte {
    // 判断缺少几位长度。最少1,最多 blockSize
    padding: = blockSize - len(data) % blockSize
        // 补足位数。把切片[]byte{byte(padding)}复制padding个
    padText: = bytes.Repeat([] byte {
        byte(padding)
    }, padding)
    return append(data, padText...)
}

// pkcs7UnPadding 填充的反向操作
func pkcs7UnPadding(data[] byte)([] byte, error) {
    length: = len(data)
    if length == 0 {
        return nil, errors.New("加密字符串错误!")
    }
    // 获取填充的个数
    unPadding: = int(data[length - 1])
    return data[: (length - unPadding)],
    nil
}
2 对文件加解密
此部分是在字符串加解密基础上,先读取文件内容,然后和加密字符串一样,将 []byte 类型的数据加密即可。对于单行超大文本文件,加密时就需要分片去读,加密后字符串写入文件中,每次加密写入一行,一定要换行,不然解密的时候区分不出来。非单行的可以逐行加密,密文也是逐行写入文本中。解密时,逐行读取解密文件,每一行为一个密文字串,将其解密,写入到文本中。
package main

import (
    "bufio"
    "bytes"
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "errors"
    "fmt"
    "os"
    "time"
)

func main() {
    startTime: = time.Now()
        // EncryptFile("file.txt", "secuityfile.txt")
    DecryptFile("encryptFile_secuityfile.txt", "file_new.txt")
    fmt.Printf("耗时:%v", time.Since(startTime))
}

var PwdKey = [] byte("ABCDABCDABCDABCD") // 三种密码标准:128 位、192 位和 256 位,对应字符串位数 16、32、64

// EncryptByAes Aes加密 后 base64 再加
func EncryptByAes(data[] byte)(string, error) {
    res, err: = AesEncrypt(data, PwdKey)
    if err != nil {
        return "", err
    }
    return base64.StdEncoding.EncodeToString(res), nil
}

// DecryptByAes Aes 解密
func DecryptByAes(data string)([] byte, error) {
    dataByte, err: = base64.StdEncoding.DecodeString(data)
    if err != nil {
        return nil, err
    }
    return AesDecrypt(dataByte, PwdKey)
}

// 加密
func AesEncrypt(data[] byte, key[] byte)([] byte, error) {
    // 创建加密实例
    block, err: = aes.NewCipher(key)
    if err != nil {
            return nil, err
        }
        // 判断加密快的大小
    blockSize: = block.BlockSize()
        // 填充
    encryptBytes: = pkcs7Padding(data, blockSize)
        // 初始化加密数据接收切片
    crypted: = make([] byte, len(encryptBytes))
        // 使用cbc加密模式
    blockMode: = cipher.NewCBCEncrypter(block, key[: blockSize]) // Cipher Block Chaining:加密块链
        // 执行加密
    blockMode.CryptBlocks(crypted, encryptBytes)
    return crypted, nil
}

// 解密
func AesDecrypt(data[] byte, key[] byte)([] byte, error) {
    // 创建实例
    block, err: = aes.NewCipher(key)
    if err != nil {
            return nil, err
        }
        // 获取块的大小
    blockSize: = block.BlockSize()
        // 使用cbc
    blockMode: = cipher.NewCBCDecrypter(block, key[: blockSize]) // Cipher Block Chaining:加密块链
        // 初始化解密数据接收切片
    crypted: = make([] byte, len(data))
        // 执行解密
    blockMode.CryptBlocks(crypted, data)
        // 去除填充
    crypted, err = pkcs7UnPadding(crypted)
    if err != nil {
        return nil, err
    }
    return crypted, nil
}

// pkcs7Padding 填充
func pkcs7Padding(data[] byte, blockSize int)[] byte {
    // 判断缺少几位长度。最少1,最多 blockSize
    padding: = blockSize - len(data) % blockSize
        // 补足位数。把切片[]byte{byte(padding)}复制padding个
    padText: = bytes.Repeat([] byte {
        byte(padding)
    }, padding)
    return append(data, padText...)
}

// pkcs7UnPadding 填充的反向操作
func pkcs7UnPadding(data[] byte)([] byte, error) {
    length: = len(data)
    if length == 0 {
        return nil, errors.New("加密字符串错误!")
    }
    // 获取填充的个数
    unPadding: = int(data[length - 1])
    return data[: (length - unPadding)],
    nil
}

// EncryptFile 文件加密,filePath 需要加密的文件路径 ,fName加密后文件名
func EncryptFile(filePath, fName string)(err error) {
    f, err: = os.Open(filePath)
    if err != nil {
        fmt.Println("未找到文件")
        return
    }
    defer f.Close()
    fInfo, _: = f.Stat()
    fLen: = fInfo.Size()
    fmt.Println("待处理文件大小:", fLen)
    maxLen: = 1024 * 1024 * 100 // 100mb  每 100mb 进行加密一次
    var forNum int64 = 0
    getLen: = fLen
    if fLen > int64(maxLen) {
            getLen = int64(maxLen)
            forNum = fLen / int64(maxLen)
            fmt.Println("需要加密次数:", forNum + 1)
        }
        // 加密后存储的文件
    ff, err: = os.OpenFile("encryptFile_" + fName, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
    if err != nil {
        fmt.Println("文件写入错误")
        return err
    }
    defer ff.Close()
        // 循环加密,并写入文件
    for i: = 0;
    i < int(forNum + 1);
    i++{
        a: = make([] byte, getLen)
        n,
        err: = f.Read(a)
        if err != nil {
            fmt.Println("文件读取错误")
            return err
        }
        getByte,
        err: = EncryptByAes(a[: n])
        if err != nil {
            fmt.Println("加密错误")
            return err
        }
        // 换行处理,有点乱了,想到更好的再改
        getBytes: = append([] byte(getByte), [] byte("\n")...)
            // 写入
        buf: = bufio.NewWriter(ff)
        buf.WriteString(string(getBytes[: ]))
        buf.Flush()
    }
    ffInfo, _: = ff.Stat()
    fmt.Printf("文件加密成功,生成文件名为:%s,文件大小为:%v Byte \n", ffInfo.Name(), ffInfo.Size())
    return nil
}

// DecryptFile 文件解密
func DecryptFile(filePath, fName string)(err error) {
    f, err: = os.Open(filePath)
    if err != nil {
        fmt.Println("未找到文件")
        return
    }
    defer f.Close()
    fInfo, _: = f.Stat()
    fmt.Println("待处理文件大小:", fInfo.Size())

    br: = bufio.NewReader(f)
    ff, err: = os.OpenFile("decryptFile_" + fName, os.O_WRONLY | os.O_CREATE | os.O_APPEND, 0666)
    if err != nil {
        fmt.Println("文件写入错误")
        return err
    }
    defer ff.Close()
    num: = 0
        // 逐行读取密文,进行解密,写入文件
    for {
        num = num + 1
        a, err: = br.ReadString('\n')
        if err != nil {
            break
        }
        getByte, err: = DecryptByAes(a)
        if err != nil {
            fmt.Println("解密错误")
            return err
        }
        buf: = bufio.NewWriter(ff)
        buf.Write(getByte)
        buf.Flush()
    }
    fmt.Println("解密次数:", num)
    ffInfo, _: = ff.Stat()
    fmt.Printf("文件解密成功,生成文件名为:%s,文件大小为:%v Byte \n", ffInfo.Name(), ffInfo.Size())
    return
}


3 明文长度与密文长度关系

n 明文长度 密文长度
1 0~15 24
2 16~31 44
3 32~47 64
4 48~63 88
5 64~79 108
6 80~95 128
7 96~111 152
... ... ...
n 16(n-1) ~ (16n-1) 20n+(n/3+1)x4     (/ :除法取整)

用户评论