doupafu6980 2015-12-05 17:00
浏览 81
已采纳

将Python AES加密算法移植到Golang

I am trying to port the following Python AES file encryption routines over to Go:

def derive_key_and_iv(password, salt, key_length, iv_length):
    d = d_i = ''
    while len(d) < key_length + iv_length:
        d_i = md5(d_i + password + salt).digest()
        d += d_i
    return d[:key_length], d[key_length:key_length+iv_length]


def encrypt(in_file, out_file, password, key_length=32):
    bs = AES.block_size
    salt = Random.new().read(bs - len('Salted__'))
    key, iv = derive_key_and_iv(password, salt, key_length, bs)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    out_file.write('Salted__' + salt)
    finished = False
    while not finished:
        chunk = in_file.read(1024 * bs)
        if len(chunk) == 0 or len(chunk) % bs != 0:
            padding_length = (bs - len(chunk) % bs) or bs
            chunk += padding_length * chr(padding_length)
            finished = True
        out_file.write(cipher.encrypt(chunk))


def decrypt(in_file, out_file, password, key_length=32):
    bs = AES.block_size
    print(bs)
    salt = in_file.read(bs)[len('Salted__'):]
    key, iv = derive_key_and_iv(password, salt, key_length, bs)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    next_chunk = ''
    finished = False
    while not finished:
        chunk, next_chunk = next_chunk, cipher.decrypt(in_file.read(1024 * bs))
        if len(next_chunk) == 0:
            padding_length = ord(chunk[-1])
            chunk = chunk[:-padding_length]
            finished = True
        out_file.write(chunk)

I have the following Go routines coded up but I'm not quite able to get it working. I am trying to get the encryption routines working in Go for callers that call the decrypt in Python and C so I'm really only interested in figuring out how to get my Golang encryption routine working but have included all the Python bits for clarity.

My current Go routines look like this:

package main
import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/base64"
    "errors"
    "fmt"
    "io"
    "log"     
    "crypto/md5"  
    "os"
    )


func pyEncrypt(password []byte, pathToInFile string, pathToOutFile string){
    bs := int(aes.BlockSize)
    salt := make([]byte, aes.BlockSize - len("Salted__")) 
    _, err := rand.Read(salt)
    if err != nil {panic(err)}

    key, iv := deriveKeyAndIV(password, salt, bs)   
    block, err := aes.NewCipher(key)
    if err != nil {panic(err)}

    cfb := cipher.NewCFBEncrypter(block, iv)

    fin, err := os.Open(pathToInFile)
    if err != nil {panic(err)}
    defer fin.Close()

    fout, err := os.Create(pathToOutFile)
    if err != nil {panic(err)}
    defer fout.Close()

    _, err = fout.Write([]byte("Salted__")) 
    if err != nil {panic(err)}
    _, err = fout.Write(salt)
    if err != nil {panic(err)}

    for true{
        ciphertext := make([]byte, 1024 *bs)
        chunk := make([]byte, 1024 * bs)
        _, err := fin.Read(chunk)
        if err == io.EOF{
        break
        }else if err != nil{
            panic(err)
        }
        cfb.XORKeyStream(ciphertext, chunk)     
        fout.Write(ciphertext)
    }
}


func deriveKeyAndIV(password []byte, salt []byte, bs int) ([]byte, []byte) {
    var digest []byte
    hash := md5.New()
    out := make([]byte, 32 + bs) //right now I'm just matching the default key size (32) from the python script so 32 represents the default from python
    for i := 0; i < 32 + bs ; i += len(digest) {
        hash.Reset()
        hash.Write(digest)
        hash.Write(password)
        hash.Write(salt)
        digest = hash.Sum(digest[:0])
        copy(out[i:], digest)
    }
    return out[:32], out[32:32+bs] //matching the default key size from Python as that is what the application uses
}

func main() {
    pwd := []byte("test123")

    pyEncrypt(pwd, "/home/chris/pt.txt", "/home/chris/genc.txt")    
}

Right now it runs, lol, generates an encrypted file that looks right and the Python "decrypts" without error but it generates gibberish and doesn't actually produce the clear text. The Python routines work by stand-alone but I can't get my Golang encrypt producing output that the Python decrypt can decrypt. I have to match the Python encryption routine for compatibility with the callers. Do you see what I'm doing wrong in my Golang encryption routine? Thank you so much for your assistance.

  • 写回答

1条回答 默认 最新

  • duanbogan5878 2015-12-07 01:15
    关注

    Here is the working encryption routine:

    func pyEncrypt(password string, pathToInFile string, pathToOutFile string){
        bs := int(aes.BlockSize)
        salt := make([]byte, aes.BlockSize - len("Salted__")) 
        _, err := rand.Read(salt)
        if err != nil {panic(err)}
    
        key, iv := deriveKeyAndIV([]byte(password), salt, bs)   
        block, err := aes.NewCipher(key)
        if err != nil {panic(err)}
    
        cbc := cipher.NewCBCEncrypter(block, iv)
    
        fin, err := os.Open(pathToInFile)
        if err != nil {panic(err)}
        defer fin.Close()
    
        fout, err := os.Create(pathToOutFile)
        if err != nil {panic(err)}
        defer fout.Close()
    
        _,err = fout.Write([]byte("Salted__"))
        if err != nil {panic(err)}
        _,err = fout.Write(salt)
        if err != nil {panic(err)}
    
        for true{
            chunk := make([]byte, 1024 * bs)
    
            n,err := fin.Read(chunk)
            if err == io.EOF{
            break
            }else if err != nil{
                panic(err)
            }
    
            if n == 0 || n % bs != 0 {//need to pad up to block size :bs
                paddingLength := (bs - n % bs) 
                paddingChr := []byte(string(rune(paddingLength)))
                paddingBytes := make([]byte, paddingLength)
    
                for i := 0; i < paddingLength; i++{
                    paddingBytes[i] = paddingChr[0]
                }
    
                chunk = append(chunk[0:n], []byte(paddingBytes)...)
            }else{
                chunk = chunk[0:n]//no padding needed           
            }
    
            ciphertext := make([]byte, len(chunk))
            cbc.CryptBlocks(ciphertext,chunk)
            fout.Write(ciphertext)
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 while循环中OLED显示中断中的数据不正确
  • ¥15 这个视频里的stm32f4代码是怎么写的
  • ¥15 串口发送数据和接收数据
  • ¥15 JNA调用DLL报堆栈溢出错误(0xC00000FD)
  • ¥15 请教SGeMs软件的使用
  • ¥15 自己用vb.net编写了一个dll文件,如何只给授权的用户使用这个dll文件进行打包编译,未授权用户不能进行打包编译操作?
  • ¥50 深度学习运行代码直接中断
  • ¥20 需要完整的共散射点成像代码
  • ¥15 编写vba代码实现数据录入工作
  • ¥15 做过TCL海信电视小米电视相关影视会员软件私我