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

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

Different Results in Go and Pycrypto when using AES-CFB

问题

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

以下是Python示例:

  1. import Crypto.Cipher
  2. import Crypto.Hash.HMAC
  3. import Crypto.Hash.SHA256
  4. import Crypto.PublicKey.RSA
  5. from binascii import hexlify, unhexlify
  6. #encrypt
  7. payload = unhexlify("abababababababababababababababababababababababababababababababab")
  8. password = unhexlify("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")
  9. iv = unhexlify("00000000000000000000000000000000")
  10. print "IV: ", hexlify(iv), "len: ", len(iv)
  11. print "Password length: ", len(password)
  12. cipher = Crypto.Cipher.AES.new(
  13. key=password,
  14. mode=Crypto.Cipher.AES.MODE_CFB,
  15. IV=iv)
  16. payload = cipher.encrypt(payload)
  17. print hexlify(payload) #dbf6b1877ba903330cb9cf0c4f530d40bf77fe2bf505820e993741c7f698ad6b

以下是Go示例:

  1. package main
  2. import (
  3. "fmt"
  4. "crypto/cipher"
  5. "crypto/aes"
  6. "encoding/hex"
  7. )
  8. // encrypt
  9. func main() {
  10. payload, err1 := hex.DecodeString("abababababababababababababababababababababababababababababababab")
  11. password, err2 := hex.DecodeString("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")
  12. iv, err3 := hex.DecodeString("00000000000000000000000000000000")
  13. if err1 != nil {
  14. fmt.Printf("error 1: %v", err1)
  15. return
  16. }
  17. if err2 != nil {
  18. fmt.Printf("error 2: %v", err2)
  19. return
  20. }
  21. if err3 != nil {
  22. fmt.Printf("error 3: %v", err3)
  23. return
  24. }
  25. aesBlock, err4 := aes.NewCipher(password)
  26. fmt.Printf("IV length:%v\n", len(iv))
  27. fmt.Printf("password length:%v\n", len(password))
  28. if err4 != nil {
  29. fmt.Printf("error 4: %v", err4)
  30. return
  31. }
  32. cfbDecrypter := cipher.NewCFBEncrypter(aesBlock, iv)
  33. cfbDecrypter.XORKeyStream(payload, payload)
  34. fmt.Printf("%v\n", hex.EncodeToString(payload)) // db70cd9e6904359cb848410bfa38d7d0a47b594f7eff72d547d3772c9d4f5dbe
  35. }

这是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:

  1. import Crypto.Cipher
  2. import Crypto.Hash.HMAC
  3. import Crypto.Hash.SHA256
  4. import Crypto.PublicKey.RSA
  5. from binascii import hexlify, unhexlify
  6. #encrypt
  7. payload = unhexlify("abababababababababababababababababababababababababababababababab")
  8. password = unhexlify("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")
  9. iv = unhexlify("00000000000000000000000000000000")
  10. print "IV: ", hexlify(iv), "len: ", len(iv)
  11. print "Password length: ", len(password)
  12. cipher = Crypto.Cipher.AES.new(
  13. key=password,
  14. mode=Crypto.Cipher.AES.MODE_CFB,
  15. IV=iv)
  16. payload = cipher.encrypt(payload)
  17. print hexlify(payload) #dbf6b1877ba903330cb9cf0c4f530d40bf77fe2bf505820e993741c7f698ad6b

And this is the Go sample:

  1. package main
  2. import (
  3. "fmt"
  4. "crypto/cipher"
  5. "crypto/aes"
  6. "encoding/hex"
  7. )
  8. // encrypt
  9. func main() {
  10. payload, err1 := hex.DecodeString("abababababababababababababababababababababababababababababababab")
  11. password, err2 := hex.DecodeString("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")
  12. iv, err3 := hex.DecodeString("00000000000000000000000000000000")
  13. if err1 != nil {
  14. fmt.Printf("error 1: %v", err1)
  15. return
  16. }
  17. if err2 != nil {
  18. fmt.Printf("error 2: %v", err2)
  19. return
  20. }
  21. if err3 != nil {
  22. fmt.Printf("error 3: %v", err3)
  23. return
  24. }
  25. aesBlock, err4 := aes.NewCipher(password)
  26. fmt.Printf("IV length:%v\n", len(iv))
  27. fmt.Printf("password length:%v\n", len(password))
  28. if err4 != nil {
  29. fmt.Printf("error 4: %v", err4)
  30. return
  31. }
  32. cfbDecrypter := cipher.NewCFBEncrypter(aesBlock, iv)
  33. cfbDecrypter.XORKeyStream(payload, payload)
  34. fmt.Printf("%v\n", hex.EncodeToString(payload)) // db70cd9e6904359cb848410bfa38d7d0a47b594f7eff72d547d3772c9d4f5dbe
  35. }

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实现,可以使用以下代码:

  1. import "crypto/cipher"
  2. // CFB流,分段大小为8位
  3. // 参考:http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
  4. type cfb8 struct {
  5. b cipher.Block
  6. blockSize int
  7. in []byte
  8. out []byte
  9. decrypt bool
  10. }
  11. func (x *cfb8) XORKeyStream(dst, src []byte) {
  12. for i := range src {
  13. x.b.Encrypt(x.out, x.in)
  14. copy(x.in[:x.blockSize-1], x.in[1:])
  15. if x.decrypt {
  16. x.in[x.blockSize-1] = src[i]
  17. }
  18. dst[i] = src[i] ^ x.out[0]
  19. if !x.decrypt {
  20. x.in[x.blockSize-1] = dst[i]
  21. }
  22. }
  23. }
  24. // NewCFB8Encrypter 返回一个使用密码反馈模式(分段大小为8)进行加密的流,使用给定的Block。iv的长度必须与Block的块大小相同。
  25. func newCFB8Encrypter(block cipher.Block, iv []byte) cipher.Stream {
  26. return newCFB8(block, iv, false)
  27. }
  28. // NewCFB8Decrypter 返回一个使用密码反馈模式(分段大小为8)进行解密的流,使用给定的Block。iv的长度必须与Block的块大小相同。
  29. func newCFB8Decrypter(block cipher.Block, iv []byte) cipher.Stream {
  30. return newCFB8(block, iv, true)
  31. }
  32. func newCFB8(block cipher.Block, iv []byte, decrypt bool) cipher.Stream {
  33. blockSize := block.BlockSize()
  34. if len(iv) != blockSize {
  35. // 堆栈跟踪将指示是解密还是加密
  36. panic("cipher.newCFB: IV length must equal block size")
  37. }
  38. x := &cfb8{
  39. b: block,
  40. blockSize: blockSize,
  41. out: make([]byte, blockSize),
  42. in: make([]byte, blockSize),
  43. decrypt: decrypt,
  44. }
  45. copy(x.in, iv)
  46. return x
  47. }

希望对你有帮助!

英文:

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

  1. import "crypto/cipher"
  2. // CFB stream with 8 bit segment size
  3. // See http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
  4. type cfb8 struct {
  5. b cipher.Block
  6. blockSize int
  7. in []byte
  8. out []byte
  9. decrypt bool
  10. }
  11. func (x *cfb8) XORKeyStream(dst, src []byte) {
  12. for i := range src {
  13. x.b.Encrypt(x.out, x.in)
  14. copy(x.in[:x.blockSize-1], x.in[1:])
  15. if x.decrypt {
  16. x.in[x.blockSize-1] = src[i]
  17. }
  18. dst[i] = src[i] ^ x.out[0]
  19. if !x.decrypt {
  20. x.in[x.blockSize-1] = dst[i]
  21. }
  22. }
  23. }
  24. // NewCFB8Encrypter returns a Stream which encrypts with cipher feedback mode
  25. // (segment size = 8), using the given Block. The iv must be the same length as
  26. // the Block's block size.
  27. func newCFB8Encrypter(block cipher.Block, iv []byte) cipher.Stream {
  28. return newCFB8(block, iv, false)
  29. }
  30. // NewCFB8Decrypter returns a Stream which decrypts with cipher feedback mode
  31. // (segment size = 8), using the given Block. The iv must be the same length as
  32. // the Block's block size.
  33. func newCFB8Decrypter(block cipher.Block, iv []byte) cipher.Stream {
  34. return newCFB8(block, iv, true)
  35. }
  36. func newCFB8(block cipher.Block, iv []byte, decrypt bool) cipher.Stream {
  37. blockSize := block.BlockSize()
  38. if len(iv) != blockSize {
  39. // stack trace will indicate whether it was de or encryption
  40. panic("cipher.newCFB: IV length must equal block size")
  41. }
  42. x := &cfb8{
  43. b: block,
  44. blockSize: blockSize,
  45. out: make([]byte, blockSize),
  46. in: make([]byte, blockSize),
  47. decrypt: decrypt,
  48. }
  49. copy(x.in, iv)
  50. return x
  51. }

答案3

得分: 6

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

  1. Crypto.Cipher.AES.new(
  2. key=password,
  3. mode=Crypto.Cipher.AES.MODE_CFB,
  4. IV=iv,
  5. segment_size=AES.block_size*8
  6. )
英文:

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:

  1. Crypto.Cipher.AES.new(
  2. key=password,
  3. mode=Crypto.Cipher.AES.MODE_CFB,
  4. IV=iv,
  5. segment_size=AES.block_size*8
  6. )

答案4

得分: 1

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

最终的代码如下:

  1. import M2Crypto.EVP
  2. iv = ciphertext[:16]
  3. ciphertext = ciphertext[16:]
  4. cipher = M2Crypto.EVP.Cipher('aes_256_cfb', t, iv, 0)
  5. text = cipher.update(ciphertext)
  6. print text

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

英文:

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

Final code looks like:

  1. import M2Crypto.EVP
  2. iv = ciphertext[:16]
  3. ciphertext = ciphertext[16:]
  4. cipher = M2Crypto.EVP.Cipher('aes_256_cfb', t, iv, 0)
  5. text = cipher.update(ciphertext)
  6. print text

Works perfect without need to change something in Go.

答案5

得分: -1

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

  1. # golang encode
  2. padNum = len(data) % 16
  3. if padNum != 0:
  4. for i in range(16 - padNum):
  5. data.append(',')
  6. # python decode
  7. 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):

  1. # golang encode
  2. padNum := len(data) % 16
  3. if padNum != 0 {
  4. for i := 0; i < 16-padNum; i++ {
  5. data = append(data, ',')
  6. }
  7. }
  8. # python decode
  9. 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:

确定