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

报告相同问题?

悬赏问题

  • ¥30 Matlab打开默认名称带有/的光谱数据
  • ¥50 easyExcel模板 动态单元格合并列
  • ¥15 res.rows如何取值使用
  • ¥15 在odoo17开发环境中,怎么实现库存管理系统,或独立模块设计与AGV小车对接?开发方面应如何设计和开发?请详细解释MES或WMS在与AGV小车对接时需完成的设计和开发
  • ¥15 CSP算法实现EEG特征提取,哪一步错了?
  • ¥15 游戏盾如何溯源服务器真实ip?需要30个字。后面的字是凑数的
  • ¥15 vue3前端取消收藏的不会引用collectId
  • ¥15 delphi7 HMAC_SHA256方式加密
  • ¥15 关于#qt#的问题:我想实现qcustomplot完成坐标轴
  • ¥15 下列c语言代码为何输出了多余的空格