AES256 encryption with golang

huangapple go评论105阅读模式
英文:

AES256 encryption with golang

问题

我在golang中编写了一个快速函数,用于在将有效负载写入磁盘之前将其加密为AES256 CBC字符串。程序(一旦编译)似乎正在执行此操作(使用此网站进行解密进行确认),但是使用此OpenSSL命令时,我遇到了最终块长度错误。有人可以帮助我吗?谢谢!

密钥:

export AES_KEY=$(python -c 'import uuid;print(uuid.uuid4().hex)')
export AES_IV=$(python -c 'import uuid;print(uuid.uuid4().hex[:16])')
func AesEncrypt(plaintext string) (string, error) {
    key := GetEnv("AES_KEY", "")
    iv := GetEnv("AES_IV", "")
    if key == "" || iv == "" {
        return "", errors.New("AES_KEY and AES_IV must be set")
    }
    bKey := []byte(key)
    bIV := []byte(iv)
    bPlaintext := PKCS5Padding([]byte(plaintext), aes.BlockSize)
    block, err := aes.NewCipher(bKey)
    if err != nil {
        return "", err
    }
    ciphertext := make([]byte, len(bPlaintext))
    mode := cipher.NewCBCEncrypter(block, bIV)
    mode.CryptBlocks(ciphertext, bPlaintext)
    return base64.StdEncoding.EncodeToString(ciphertext), nil
    // return hex.EncodeToString(ciphertext), nil
}

func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
    padding := (blockSize - len(ciphertext)%blockSize)
    padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(ciphertext, padtext...)
}

func AesDecrypt(ciphertext string) (string, error) {
    key := GetEnv("AES_KEY", "")
    iv := GetEnv("AES_IV", "")
    if key == "" || iv == "" {
        return "", errors.New("AES_KEY and AES_IV must be set")
    }
    bKey := []byte(key)
    bIV := []byte(iv)
    // base64 decode
    cipherTextDecoded, err := base64.StdEncoding.DecodeString(ciphertext)
    if err != nil {
        return "", err
    }
    // cipherTextDecoded, err := hex.DecodeString(cipherText)

    block, err := aes.NewCipher(bKey)
    if err != nil {
        return "", err
    }

    mode := cipher.NewCBCDecrypter(block, bIV)
    mode.CryptBlocks([]byte(cipherTextDecoded), []byte(cipherTextDecoded))
    return string(cipherTextDecoded), nil
}

使用OpenSSL命令解密(在使用go二进制文件导出文件后):

openssl aes-256-cbc -d -a -v -nosalt \
    -K $AES_KEY \
    -iv $AES_IV \
    -in variables.enc -out variables.dec

结果为:

bad decrypt
8503165248:error:06FFF06D:digital envelope routines:CRYPTO_internal:wrong final block length:/AppleInternal/Library/BuildRoots/9e200cfa-7d96-11ed-886f-a23c4f261b56/Library/Caches/com.apple.xbs/Sources/libressl/libressl-3.3/crypto/evp/evp_enc.c:540:
英文:

I wrote a quick function in golang to encrypt my payload as an AES256 CBC string before writing to disk. The program (once compiled) appears to be doing just that (as confirmed using this site to decrypt), however using this OpenSSL command I get a final block length error. Can someone please help me? Thanks!

Keys:

export AES_KEY=$(python -c 'import uuid;print(uuid.uuid4().hex)')
export AES_IV=$(python -c 'import uuid;print(uuid.uuid4().hex[:16])')
func AesEncrypt(plaintext string) (string, error) {
key := GetEnv("AES_KEY", "")
iv := GetEnv("AES_IV", "")
if key == "" || iv == "" {
return "", errors.New("AES_KEY and AES_IV must be set")
}
bKey := []byte(key)
bIV := []byte(iv)
bPlaintext := PKCS5Padding([]byte(plaintext), aes.BlockSize)
block, err := aes.NewCipher(bKey)
if err != nil {
return "", err
}
ciphertext := make([]byte, len(bPlaintext))
mode := cipher.NewCBCEncrypter(block, bIV)
mode.CryptBlocks(ciphertext, bPlaintext)
return base64.StdEncoding.EncodeToString(ciphertext), nil
// return hex.EncodeToString(ciphertext), nil
}
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := (blockSize - len(ciphertext)%blockSize)
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func AesDecrypt(ciphertext string) (string, error) {
key := GetEnv("AES_KEY", "")
iv := GetEnv("AES_IV", "")
if key == "" || iv == "" {
return "", errors.New("AES_KEY and AES_IV must be set")
}
bKey := []byte(key)
bIV := []byte(iv)
// base64 decode
cipherTextDecoded, err := base64.StdEncoding.DecodeString(ciphertext)
if err != nil {
return "", err
}
// cipherTextDecoded, err := hex.DecodeString(cipherText)
block, err := aes.NewCipher(bKey)
if err != nil {
return "", err
}
mode := cipher.NewCBCDecrypter(block, bIV)
mode.CryptBlocks([]byte(cipherTextDecoded), []byte(cipherTextDecoded))
return string(cipherTextDecoded), nil
}

OpenSSL command to decrypt (after exporting file using go binary):

openssl aes-256-cbc -d -a -v -nosalt \
    -K $AES_KEY \
    -iv $AES_IV \
    -in variables.enc -out variables.dec

results in:

bad decrypt
8503165248:error:06FFF06D:digital envelope routines:CRYPTO_internal:wrong final block length:/AppleInternal/Library/BuildRoots/9e200cfa-7d96-11ed-886f-a23c4f261b56/Library/Caches/com.apple.xbs/Sources/libressl/libressl-3.3/crypto/evp/evp_enc.c:540:

答案1

得分: 1

解密要使用OpenSSL(参见enc):

  • 密钥和初始化向量(IV)必须在OpenSSL语句中以十六进制编码指定。
  • 必须除了使用-a选项外,还要设置-A选项,以便从单行读取数据。

这两个选项都缺失了。如果添加了这些选项,解密将在OpenSSL中正常工作。


测试:

使用Python代码生成以下密钥和IV:

密钥:eaba2d73e2474eed9c3352f5aefe50e3
IV:26e67818dfa848c2

假设GetEnv()返回由Python代码生成的字符串,密钥和IV是两个字符串的UTF8编码结果(例如,bKey := []byte(key))。然后,Go代码为明文生成了以下密文:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

密文为:

157JLDOTKOuOV2UGaa+HcZUyZrjIRA/gbUGYcW5IQZQmNF4McKoDztk3gJcnqnSGBKGDG+beHvmmz5AS1vr1fjIKmpgOsIK8e4ZmTlg2z/nL5h1C8/9+vYTCZ8U3l/vNdlvrObdzEIzu5m/4mEWgZlvgZo+vsN8t9gZfj5Gw7uc=

可以使用以下命令在OpenSSL中解密:

openssl aes-256-cbc -d -a -A -nosalt -K 6561626132643733653234373465656439633333353266356165666535306533 -iv 32366536373831386466613834386332 -in <path to encrypted data file> -out <path to decrypted data file>

其中,密钥和IV以十六进制编码指定,并设置了-A选项(请注意,当设置了-K和-iv时,-nosalt选项不起作用)。


备注:

  • 在Go代码中,缺少去填充(unpadding)操作。顺便提一下,pkcs7pad包实现了PKCS#7填充(尽管PKCS5Padding()似乎也可以使用)。
  • AES密钥应该是一个随机字节序列。UUID.hex返回一个32字节的小写十六进制字符串。当将其用作AES-256的密钥时,安全性会降低,因为每个字节被缩小到16个值(而不是256个值)。
英文:

For decryption to work with OpenSSL (s. enc):

  • key and IV must be specified hex encoded in the OpenSSL statement.
  • the -A option must be set in addition to -a so that the data is to be read from a single line.

Both are missing. If this is added, decryption works with OpenSSL.


Test:

With the Python code, e.g. the following key and IV are generated:

Key: eaba2d73e2474eed9c3352f5aefe50e3
IV:  26e67818dfa848c2

Assuming that GetEnv() returns the strings generated by the Python code, key and IV result as UTF8 encoding of both strings (e.g. bKey := []byte(key)). The Go code then generates for the plaintext:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

the ciphertext:

157JLDOTKOuOV2UGaa+HcZUyZrjIRA/gbUGYcW5IQZQmNF4McKoDztk3gJcnqnSGBKGDG+beHvmmz5AS1vr1fjIKmpgOsIK8e4ZmTlg2z/nL5h1C8/9+vYTCZ8U3l/vNdlvrObdzEIzu5m/4mEWgZlvgZo+vsN8t9gZfj5Gw7uc=

This can be decrypted with OpenSSL as follows:

openssl aes-256-cbc -d -a -A -nosalt -K 6561626132643733653234373465656439633333353266356165666535306533 -iv 32366536373831386466613834386332 -in <path to encrypted data file> -out <path to decrypted data file>

where key and IV are specified hex encoded and the -A option is set (note that the -nosalt option has no effect when -K and -iv are set.)


Notes:

  • In the Go code, the unpadding is missing. By the way, PKCS#7 is implemented by the pkcs7pad package (although PKCS5Padding() seems to be OK).
  • An AES key should be a random byte sequence. UUID.hex returns a 32 bytes lowercase hex string. When this is used as key for AES-256, security is reduced because each byte is narrowed to 16 values (versus 256 values).

huangapple
  • 本文由 发表于 2023年3月15日 07:43:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/75739344.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定