英文:
Porting Python AES encryption routies to Golang
问题
我正在尝试将以下Python AES文件加密例程移植到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)
我已经编写了以下Go语言例程,但是我无法使其正常工作。我正在尝试让Go语言的加密例程与调用Python和C的解密例程配合使用,所以我只关心如何使我的Go语言加密例程正常工作,但为了清晰起见,我包含了所有Python代码。
我的当前Go语言例程如下:
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")
}
目前它可以运行,生成一个看起来正确的加密文件,Python可以“解密”而不报错,但它生成的是无意义的内容,实际上并没有产生明文。Python例程可以独立工作,但我无法使我的Go语言加密例程生成Python可以解密的输出。我必须与Python的加密例程保持一致,以便与调用者兼容。你能看出我在Go语言加密例程中做错了什么吗?非常感谢你的帮助。
英文:
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
得分: 0
以下是工作中的加密例程:
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)
}
}
希望对你有帮助!
英文:
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)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论