AES 加密 Golang 和 Python

我正在为自己做一个有趣的副项目。一个 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 中解密,反之亦然。

如您所见,消息已解密,但最终出现在字符串的末尾?


海绵宝宝撒
浏览 187回答 2
2回答

幕布斯6054654

Python 使用 8 位段,而 Go 使用 128 位段,因此第一个字符起作用但后面的字符不起作用的原因是因为每个段都依赖于前一个,因此不同的段大小破坏了链。我为 Python 制作了这些 URL 安全(非填充 base64 编码)加密/解密函数,以便像 Go 一样(当您指定时block_segments=True)有选择地加密。def decrypt(key, value, block_segments=False):&nbsp; &nbsp; # The base64 library fails if value is Unicode. Luckily, base64 is ASCII-safe.&nbsp; &nbsp; value = str(value)&nbsp; &nbsp; # We add back the padding ("=") here so that the decode won't fail.&nbsp; &nbsp; value = base64.b64decode(value + '=' * (4 - len(value) % 4), '-_')&nbsp; &nbsp; iv, value = value[:AES.block_size], value[AES.block_size:]&nbsp; &nbsp; if block_segments:&nbsp; &nbsp; &nbsp; &nbsp; # Python uses 8-bit segments by default for legacy reasons. In order to support&nbsp; &nbsp; &nbsp; &nbsp; # languages that encrypt using 128-bit segments, without having to use data with&nbsp; &nbsp; &nbsp; &nbsp; # a length divisible by 16, we need to pad and truncate the values.&nbsp; &nbsp; &nbsp; &nbsp; remainder = len(value) % 16&nbsp; &nbsp; &nbsp; &nbsp; padded_value = value + '\0' * (16 - remainder) if remainder else value&nbsp; &nbsp; &nbsp; &nbsp; cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)&nbsp; &nbsp; &nbsp; &nbsp; # Return the decrypted string with the padding removed.&nbsp; &nbsp; &nbsp; &nbsp; return cipher.decrypt(padded_value)[:len(value)]&nbsp; &nbsp; return AES.new(key, AES.MODE_CFB, iv).decrypt(value)def encrypt(key, value, block_segments=False):&nbsp; &nbsp; iv = Random.new().read(AES.block_size)&nbsp; &nbsp; if block_segments:&nbsp; &nbsp; &nbsp; &nbsp; # See comment in decrypt for information.&nbsp; &nbsp; &nbsp; &nbsp; remainder = len(value) % 16&nbsp; &nbsp; &nbsp; &nbsp; padded_value = value + '\0' * (16 - remainder) if remainder else value&nbsp; &nbsp; &nbsp; &nbsp; cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)&nbsp; &nbsp; &nbsp; &nbsp; value = cipher.encrypt(padded_value)[:len(value)]&nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; value = AES.new(key, AES.MODE_CFB, iv).encrypt(value)&nbsp; &nbsp; # The returned value has its padding stripped to avoid query string issues.&nbsp; &nbsp; return base64.b64encode(iv + value, '-_').rstrip('=')请注意,为了安全的消息传递,您需要额外的安全功能,例如防止重放攻击的随机数。以下是 Go 等效函数:func Decrypt(key []byte, encrypted string) ([]byte, error) {&nbsp; &nbsp; ciphertext, err := base64.RawURLEncoding.DecodeString(encrypted)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return nil, err&nbsp; &nbsp; }&nbsp; &nbsp; block, err := aes.NewCipher(key)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return nil, err&nbsp; &nbsp; }&nbsp; &nbsp; if len(ciphertext) < aes.BlockSize {&nbsp; &nbsp; &nbsp; &nbsp; return nil, errors.New("ciphertext too short")&nbsp; &nbsp; }&nbsp; &nbsp; iv := ciphertext[:aes.BlockSize]&nbsp; &nbsp; ciphertext = ciphertext[aes.BlockSize:]&nbsp; &nbsp; cfb := cipher.NewCFBDecrypter(block, iv)&nbsp; &nbsp; cfb.XORKeyStream(ciphertext, ciphertext)&nbsp; &nbsp; return ciphertext, nil}func Encrypt(key, data []byte) (string, error) {&nbsp; &nbsp; block, err := aes.NewCipher(key)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return "", err&nbsp; &nbsp; }&nbsp; &nbsp; ciphertext := make([]byte, aes.BlockSize+len(data))&nbsp; &nbsp; iv := ciphertext[:aes.BlockSize]&nbsp; &nbsp; if _, err := io.ReadFull(rand.Reader, iv); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return "", err&nbsp; &nbsp; }&nbsp; &nbsp; stream := cipher.NewCFBEncrypter(block, iv)&nbsp; &nbsp; stream.XORKeyStream(ciphertext[aes.BlockSize:], data)&nbsp; &nbsp; return base64.RawURLEncoding.EncodeToString(ciphertext), nil}

PIPIONE

您忘记在 Python 解密期间切掉 IV。改变x=(cipher.decrypt(&nbsp;enc&nbsp;))到x&nbsp;=&nbsp;cipher.decrypt(&nbsp;enc[16:]&nbsp;)或者x&nbsp;=&nbsp;cipher.decrypt(&nbsp;enc&nbsp;)[16:]
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go