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)
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何用stata画出文献中常见的安慰剂检验图
  • ¥15 c语言链表结构体数据插入
  • ¥40 使用MATLAB解答线性代数问题
  • ¥15 COCOS的问题COCOS的问题
  • ¥15 FPGA-SRIO初始化失败
  • ¥15 MapReduce实现倒排索引失败
  • ¥15 ZABBIX6.0L连接数据库报错,如何解决?(操作系统-centos)
  • ¥15 找一位技术过硬的游戏pj程序员
  • ¥15 matlab生成电测深三层曲线模型代码
  • ¥50 随机森林与房贷信用风险模型