在使用AES-CFB时,Go和Pycrypto产生不同的结果。

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

Different Results in Go and Pycrypto when using AES-CFB

问题

我正在将一个Go应用程序添加到一个已经存在的Python代码库中。我一直在处理两种语言之间的加密问题。这个示例使用的是Go 1.2.1和Python 2.7.x / PyCrypto 2.7a1。

以下是Python示例:

import Crypto.Cipher
import Crypto.Hash.HMAC
import Crypto.Hash.SHA256
import Crypto.PublicKey.RSA
from binascii import hexlify, unhexlify

#encrypt
payload =  unhexlify("abababababababababababababababababababababababababababababababab")
password = unhexlify("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")
iv = unhexlify("00000000000000000000000000000000")

print "IV: ", hexlify(iv), "len: ", len(iv)
print "Password length: ", len(password)


cipher = Crypto.Cipher.AES.new(
			key=password, 
			mode=Crypto.Cipher.AES.MODE_CFB, 
			IV=iv)

payload = cipher.encrypt(payload)

print hexlify(payload) #dbf6b1877ba903330cb9cf0c4f530d40bf77fe2bf505820e993741c7f698ad6b

以下是Go示例:

package main

import (
	"fmt"
	"crypto/cipher"
	"crypto/aes"
	"encoding/hex"
)

// encrypt
func main() {
	payload, err1 := hex.DecodeString("abababababababababababababababababababababababababababababababab")
	password, err2 := hex.DecodeString("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")
	iv, err3 := hex.DecodeString("00000000000000000000000000000000")

	if err1 != nil {
		fmt.Printf("error 1: %v", err1)
		return
	}

	if err2 != nil {
		fmt.Printf("error 2: %v", err2)
		return
	}

	if err3 != nil {
		fmt.Printf("error 3: %v", err3)
		return
	}

	aesBlock, err4 := aes.NewCipher(password)

	fmt.Printf("IV length:%v\n", len(iv))
	fmt.Printf("password length:%v\n", len(password))

	if err4 != nil {
		fmt.Printf("error 4: %v", err4)
		return
	}

	cfbDecrypter := cipher.NewCFBEncrypter(aesBlock, iv)
	cfbDecrypter.XORKeyStream(payload, payload)	

	fmt.Printf("%v\n", hex.EncodeToString(payload)) // db70cd9e6904359cb848410bfa38d7d0a47b594f7eff72d547d3772c9d4f5dbe
}

这是golang链接,我找不到一个已安装PyCrypto的Python pastebin。

如标题和源所示,这两个代码片段产生了不同的密文:
Python: dbf6b1877ba903330cb9cf0c4f530d40bf77fe2bf505820e993741c7f698ad6b
Golang: db70cd9e6904359cb848410bfa38d7d0a47b594f7eff72d547d3772c9d4f5dbe

两种语言都可以解密其“本地”密文,但是它们都无法解密对方的密文。因为Python实现已经存在,所以我正在寻找一种解决方案,允许Go解密使用示例PyCrypto AES设置和密钥大小加密的密文。

英文:

I am adding a go application to an already existing python codebase. I've been having trouble dealing with encryption between the languages. This is using go 1.2.1 and Python 2.7.x / PyCrypto 2.7a1.

Here is the Python sample:

import Crypto.Cipher
import Crypto.Hash.HMAC
import Crypto.Hash.SHA256
import Crypto.PublicKey.RSA
from binascii import hexlify, unhexlify

#encrypt
payload =  unhexlify("abababababababababababababababababababababababababababababababab")
password = unhexlify("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")
iv = unhexlify("00000000000000000000000000000000")

print "IV: ", hexlify(iv), "len: ", len(iv)
print "Password length: ", len(password)


cipher = Crypto.Cipher.AES.new(
			key=password, 
			mode=Crypto.Cipher.AES.MODE_CFB, 
			IV=iv)

payload = cipher.encrypt(payload)

print hexlify(payload) #dbf6b1877ba903330cb9cf0c4f530d40bf77fe2bf505820e993741c7f698ad6b

And this is the Go sample:

package main

import (
	"fmt"
	"crypto/cipher"
	"crypto/aes"
	"encoding/hex"
)

// encrypt
func main() {
	payload, err1 := hex.DecodeString("abababababababababababababababababababababababababababababababab")
	password, err2 := hex.DecodeString("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")
	iv, err3 := hex.DecodeString("00000000000000000000000000000000")

	if err1 != nil {
		fmt.Printf("error 1: %v", err1)
		return
	}

	if err2 != nil {
		fmt.Printf("error 2: %v", err2)
		return
	}

	if err3 != nil {
		fmt.Printf("error 3: %v", err3)
		return
	}

	aesBlock, err4 := aes.NewCipher(password)

	fmt.Printf("IV length:%v\n", len(iv))
	fmt.Printf("password length:%v\n", len(password))

	if err4 != nil {
		fmt.Printf("error 4: %v", err4)
		return
	}

	cfbDecrypter := cipher.NewCFBEncrypter(aesBlock, iv)
	cfbDecrypter.XORKeyStream(payload, payload)	

	fmt.Printf("%v\n", hex.EncodeToString(payload)) // db70cd9e6904359cb848410bfa38d7d0a47b594f7eff72d547d3772c9d4f5dbe
}

Here is the golang link, I could not find a Python pastebin that had PyCrypto installed.

As suggested by the title & source, the two snippets produce different cyphertext:
Python: dbf6b1877ba903330cb9cf0c4f530d40bf77fe2bf505820e993741c7f698ad6b
Golang: db70cd9e6904359cb848410bfa38d7d0a47b594f7eff72d547d3772c9d4f5dbe

Both languages can decrypt their 'native' cypthertext, but neither can decrypt the others'. Because the python implementation already exists, I'm looking for a solution that will allow Go to decrypt cyphertext encrypted with the example PyCrypto AES settings & key size.

答案1

得分: 10

研究当前系统发现,我们的Python系统使用CFB8(8位段)。Go语言默认不支持这种方式,但是当前的CFBDecrypter / CFBEncrypter的源代码看起来可以相对容易地进行适应。

英文:

Research on the current system has revealed that our python system uses CFB8 (8 bit segments). Go does not support this out of the box, but the source code used in the current CFBDecrypter / CFBEncrypter looks like it can be adapted fairly easily.

答案2

得分: 7

如果有人正在寻找使用分段大小为8的CFB模式的Go实现,可以使用以下代码:

import "crypto/cipher"

// CFB流,分段大小为8位
// 参考:http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
type cfb8 struct {
	b         cipher.Block
	blockSize int
	in        []byte
	out       []byte

	decrypt bool
}

func (x *cfb8) XORKeyStream(dst, src []byte) {
	for i := range src {
		x.b.Encrypt(x.out, x.in)
		copy(x.in[:x.blockSize-1], x.in[1:])
		if x.decrypt {
			x.in[x.blockSize-1] = src[i]
		}
		dst[i] = src[i] ^ x.out[0]
		if !x.decrypt {
			x.in[x.blockSize-1] = dst[i]
		}
	}
}

// NewCFB8Encrypter 返回一个使用密码反馈模式(分段大小为8)进行加密的流,使用给定的Block。iv的长度必须与Block的块大小相同。
func newCFB8Encrypter(block cipher.Block, iv []byte) cipher.Stream {
	return newCFB8(block, iv, false)
}

// NewCFB8Decrypter 返回一个使用密码反馈模式(分段大小为8)进行解密的流,使用给定的Block。iv的长度必须与Block的块大小相同。
func newCFB8Decrypter(block cipher.Block, iv []byte) cipher.Stream {
	return newCFB8(block, iv, true)
}

func newCFB8(block cipher.Block, iv []byte, decrypt bool) cipher.Stream {
	blockSize := block.BlockSize()
	if len(iv) != blockSize {
		// 堆栈跟踪将指示是解密还是加密
		panic("cipher.newCFB: IV length must equal block size")
	}
	x := &cfb8{
		b:         block,
		blockSize: blockSize,
		out:       make([]byte, blockSize),
		in:        make([]byte, blockSize),
		decrypt:   decrypt,
	}
	copy(x.in, iv)

	return x
}

希望对你有帮助!

英文:

If anyone is looking for Go implementation of CFB mode with segment size = 8 you can use this:

import "crypto/cipher"
// CFB stream with 8 bit segment size
// See http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
type cfb8 struct {
b         cipher.Block
blockSize int
in        []byte
out       []byte
decrypt bool
}
func (x *cfb8) XORKeyStream(dst, src []byte) {
for i := range src {
x.b.Encrypt(x.out, x.in)
copy(x.in[:x.blockSize-1], x.in[1:])
if x.decrypt {
x.in[x.blockSize-1] = src[i]
}
dst[i] = src[i] ^ x.out[0]
if !x.decrypt {
x.in[x.blockSize-1] = dst[i]
}
}
}
// NewCFB8Encrypter returns a Stream which encrypts with cipher feedback mode
// (segment size = 8), using the given Block. The iv must be the same length as
// the Block's block size.
func newCFB8Encrypter(block cipher.Block, iv []byte) cipher.Stream {
return newCFB8(block, iv, false)
}
// NewCFB8Decrypter returns a Stream which decrypts with cipher feedback mode
// (segment size = 8), using the given Block. The iv must be the same length as
// the Block's block size.
func newCFB8Decrypter(block cipher.Block, iv []byte) cipher.Stream {
return newCFB8(block, iv, true)
}
func newCFB8(block cipher.Block, iv []byte, decrypt bool) cipher.Stream {
blockSize := block.BlockSize()
if len(iv) != blockSize {
// stack trace will indicate whether it was de or encryption
panic("cipher.newCFB: IV length must equal block size")
}
x := &cfb8{
b:         block,
blockSize: blockSize,
out:       make([]byte, blockSize),
in:        make([]byte, blockSize),
decrypt:   decrypt,
}
copy(x.in, iv)
return x
}

答案3

得分: 6

似乎如果我们将AES对象的segment_size从默认值8更改为AES.block_size*8(即128),密码可以与Go的crypto/cipher兼容,代码如下所示:

Crypto.Cipher.AES.new(
    key=password, 
    mode=Crypto.Cipher.AES.MODE_CFB, 
    IV=iv,
    segment_size=AES.block_size*8
)
英文:

It seems that the cipher can be made compatible to Go's crypto/cipher if we change segment_size of AES object from the default 8 to AES.block_size*8 (which is 128), like this:

Crypto.Cipher.AES.new(
key=password, 
mode=Crypto.Cipher.AES.MODE_CFB, 
IV=iv,
segment_size=AES.block_size*8
)

答案4

得分: 1

我发现从Python方面处理这个问题最简单的方法是使用M2Crypto库。

最终的代码如下:

import M2Crypto.EVP

iv = ciphertext[:16]
ciphertext = ciphertext[16:]

cipher = M2Crypto.EVP.Cipher('aes_256_cfb', t, iv, 0)
text = cipher.update(ciphertext)
print text

这段代码完美地工作,无需在Go中进行任何更改。

英文:

I found that easiest way to deal with this from Python side is to use M2Crypto library.

Final code looks like:

import M2Crypto.EVP
iv = ciphertext[:16]
ciphertext = ciphertext[16:]
cipher = M2Crypto.EVP.Cipher('aes_256_cfb', t, iv, 0)
text = cipher.update(ciphertext)
print text

Works perfect without need to change something in Go.

答案5

得分: -1

我用类似这样的 Python 代码进行了适配(Go 语言编码和 Python 解码):

# golang encode
padNum = len(data) % 16
if padNum != 0:
    for i in range(16 - padNum):
        data.append(',')

# python decode
cipher = AES.new(key=self.key, mode=AES.MODE_CFB, IV=iv, segment_size=128)

希望这对你有帮助!如果你还有其他问题,请随时提问。

英文:

i solve by adapt python code like this (golang encode and python decode):

# golang encode
padNum := len(data) % 16
if padNum != 0 {
for i := 0; i < 16-padNum; i++ {
data = append(data, ',')
}
}
# python decode
cipher = AES.new(key=self.key, mode=AES.MODE_CFB, IV=iv,segment_size=128)

huangapple
  • 本文由 发表于 2014年5月28日 03:54:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/23897809.html
匿名

发表评论

匿名网友

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

确定