为了账号安全,请及时绑定邮箱和手机立即绑定

AES 加密 Golang 和 Python

AES 加密 Golang 和 Python

Go
海绵宝宝撒 2021-12-20 15:11:16
我正在为自己做一个有趣的副项目。一个 golang 服务器和一个 python 客户端。我希望传输的数据被加密,但似乎无法让这两种加密方案协同工作。我是加密方面的新手,所以请像在和蹒跚学步的孩子交谈一样解释。这是我的 golang 加密函数:import (    "crypto/aes"    "crypto/cipher"    "crypto/rand"    "errors"    "io"    "fmt")func Encrypt(key, text []byte) (ciphertext []byte, err error) {    var block cipher.Block    if block, err = aes.NewCipher(key); err != nil {        return nil, err    }    ciphertext = make([]byte, aes.BlockSize+len(string(text)))    iv := ciphertext[:aes.BlockSize]    fmt.Println(aes.BlockSize)    if _, err = io.ReadFull(rand.Reader, iv); err != nil {        return    }    cfb := cipher.NewCFBEncrypter(block, iv)    cfb.XORKeyStream(ciphertext[aes.BlockSize:], text)    return}func Decrypt(key, ciphertext []byte) (plaintext []byte, err error) {    var block cipher.Block    if block, err = aes.NewCipher(key); err != nil {        return    }    if len(ciphertext) < aes.BlockSize {        err = errors.New("ciphertext too short")        return    }    iv := ciphertext[:aes.BlockSize]    ciphertext = ciphertext[aes.BlockSize:]    cfb := cipher.NewCFBDecrypter(block, iv)    cfb.XORKeyStream(ciphertext, ciphertext)    plaintext = ciphertext    return}这是我的 Python 实现: class AESCipher:    def __init__( self, key ):        self.key = key        print "INIT KEY" + hexlify(self.key)    def encrypt( self, raw ):        print "RAW STRING: " + hexlify(raw)        iv = Random.new().read( AES.block_size )        cipher = AES.new( self.key, AES.MODE_CFB, iv )        r = ( iv + cipher.encrypt( raw ) )        print "ECRYPTED STRING: " + hexlify(r)        return r    def decrypt( self, enc ):        enc = (enc)        iv = enc[:16]        cipher = AES.new(self.key, AES.MODE_CFB, iv)        x=(cipher.decrypt( enc ))        print "DECRYPTED STRING: " + hexlify(x)        return x我也无法弄清楚我的 python 函数的输出。我的 Go 例程运行良好。但我希望能够在 Go 中加密,在 python 中解密,反之亦然。如您所见,消息已解密,但最终出现在字符串的末尾?
查看完整描述

2 回答

?
幕布斯6054654

TA贡献1876条经验 获得超7个赞

Python 使用 8 位段,而 Go 使用 128 位段,因此第一个字符起作用但后面的字符不起作用的原因是因为每个段都依赖于前一个,因此不同的段大小破坏了链。


我为 Python 制作了这些 URL 安全(非填充 base64 编码)加密/解密函数,以便像 Go 一样(当您指定时block_segments=True)有选择地加密。


def decrypt(key, value, block_segments=False):

    # The base64 library fails if value is Unicode. Luckily, base64 is ASCII-safe.

    value = str(value)

    # We add back the padding ("=") here so that the decode won't fail.

    value = base64.b64decode(value + '=' * (4 - len(value) % 4), '-_')

    iv, value = value[:AES.block_size], value[AES.block_size:]

    if block_segments:

        # Python uses 8-bit segments by default for legacy reasons. In order to support

        # languages that encrypt using 128-bit segments, without having to use data with

        # a length divisible by 16, we need to pad and truncate the values.

        remainder = len(value) % 16

        padded_value = value + '\0' * (16 - remainder) if remainder else value

        cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)

        # Return the decrypted string with the padding removed.

        return cipher.decrypt(padded_value)[:len(value)]

    return AES.new(key, AES.MODE_CFB, iv).decrypt(value)



def encrypt(key, value, block_segments=False):

    iv = Random.new().read(AES.block_size)

    if block_segments:

        # See comment in decrypt for information.

        remainder = len(value) % 16

        padded_value = value + '\0' * (16 - remainder) if remainder else value

        cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)

        value = cipher.encrypt(padded_value)[:len(value)]

    else:

        value = AES.new(key, AES.MODE_CFB, iv).encrypt(value)

    # The returned value has its padding stripped to avoid query string issues.

    return base64.b64encode(iv + value, '-_').rstrip('=')

请注意,为了安全的消息传递,您需要额外的安全功能,例如防止重放攻击的随机数。


以下是 Go 等效函数:


func Decrypt(key []byte, encrypted string) ([]byte, error) {

    ciphertext, err := base64.RawURLEncoding.DecodeString(encrypted)

    if err != nil {

        return nil, err

    }

    block, err := aes.NewCipher(key)

    if err != nil {

        return nil, err

    }

    if len(ciphertext) < aes.BlockSize {

        return nil, errors.New("ciphertext too short")

    }

    iv := ciphertext[:aes.BlockSize]

    ciphertext = ciphertext[aes.BlockSize:]

    cfb := cipher.NewCFBDecrypter(block, iv)

    cfb.XORKeyStream(ciphertext, ciphertext)

    return ciphertext, nil

}


func Encrypt(key, data []byte) (string, error) {

    block, err := aes.NewCipher(key)

    if err != nil {

        return "", err

    }

    ciphertext := make([]byte, aes.BlockSize+len(data))

    iv := ciphertext[:aes.BlockSize]

    if _, err := io.ReadFull(rand.Reader, iv); err != nil {

        return "", err

    }

    stream := cipher.NewCFBEncrypter(block, iv)

    stream.XORKeyStream(ciphertext[aes.BlockSize:], data)

    return base64.RawURLEncoding.EncodeToString(ciphertext), nil

}


查看完整回答
反对 回复 2021-12-20
?
PIPIONE

TA贡献1829条经验 获得超9个赞

您忘记在 Python 解密期间切掉 IV。改变

x=(cipher.decrypt( enc ))

x = cipher.decrypt( enc[16:] )

或者

x = cipher.decrypt( enc )[16:]


查看完整回答
反对 回复 2021-12-20
  • 2 回答
  • 0 关注
  • 173 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号