dongxiaofa6359 2014-05-27 19:54
浏览 304
已采纳

使用AES-CFB时Go和Pycrypto的结果不同

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
", len(iv))
    fmt.Printf("password length:%v
", len(password))

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

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

    fmt.Printf("%v
", 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.

  • 写回答

5条回答 默认 最新

  • drgbpq5930 2014-05-27 21:53
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
  • 普通网友 2014-10-06 10:24
    关注

    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
    )
    
    评论
  • dsakktdog498483070 2016-05-15 03:26
    关注

    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
    }
    
    评论
  • douna6802 2016-07-30 14:39
    关注

    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.

    评论
  • doulan4939 2016-08-01 06:35
    关注

    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)
    
    评论
查看更多回答(4条)

报告相同问题?

悬赏问题

  • ¥15 关于#abap#的问题,请各位专家解答!
  • ¥20 内网通过公网访问外网问题
  • ¥15 怎么使请求通过cors
  • ¥15 WDM 驱动ACPI 相关疑问
  • ¥15 prism 跨窗体共享数据绑定 wpf
  • ¥15 hdl designer突然用不了系统的moduleware组件,请问有人遇到或者怎么解决吗?
  • ¥15 0基础计算机毕设,应该从哪开始?
  • ¥60 使用DKT40脑图划分ROI区域
  • ¥15 有偿解决C51单片机液晶屏12864显示问题
  • ¥15 IDEA构建失败?怎么搞