英文:
Golang - Packing and hashing binary data
问题
我正在尝试学习Golang,并且有Python的背景。我目前正在努力理解如何将变量打包成二进制格式(带有校验和)。在Python中,我会使用类似以下的代码:
import struct
import hashlib
a = 100
b = "foo\x00\x00" # 填充到固定长度
packet = struct.pack('<B5s', a, b)
digest = hashlib.sha256(packet).digest()
packet += digest
为了在Go中实现相同的功能,我尝试了以下代码:
package main
import (
"crypto/sha256"
"fmt"
"encoding/binary"
"bytes"
)
type packet struct {
a uint8
b string
}
func main() {
var p = packet{}
p.a = 1
p.b = "foo\x00\x00"
buf := new(bytes.Buffer)
binary.Write(buf, binary.LittleEndian, &p)
h := sha256.New()
h.Write(buf.Bytes())
fmt.Printf("% x\n", p)
}
然而,不幸的是,无论我如何尝试,似乎都陷入了变量类型冲突的噩梦(缓冲区、字节数组和字符串)。我希望能得到一些指导,看看我是否采取了正确的方法。
英文:
I'm attempting to learn Golang and have a background in Python. I'm currently trying to get my head around how to pack variables into a binary format (with a checksum). In Python I'd use something like:
import struct
import hashlib
a = 100
b = "foo\x00\x00" # Padded to fixed length
packet = struct.pack('<B5s', a, b)
digest = hashlib.sha256(packet).digest()
packet += digest
To do the same thing in Go, I'm trying code like this:
package main
import (
"crypto/sha256"
"fmt"
"encoding/binary"
"bytes"
)
type packet struct {
a uint8
b string
}
func main() {
var p = packet{}
p.a = 1
p.b = "foo\x00\x00"
buf := new(bytes.Buffer)
binary.Write(buf, binary.LittleEndian, &p)
h := sha256.New()
h.Write(buf.String())
fmt.Printf("% x\n", p)
}
Unfortunately, however I attack it I seem to get into a nightmare of clashing variable types (buffers, byte arrays and strings). I'd appreciate some guidance as to whether I'm taking even remotely the right approach.
答案1
得分: 5
更新为可工作的代码。
package main
import (
"bytes"
"crypto/sha256"
"encoding/binary"
"fmt"
)
type packet struct {
a uint8
b []byte
}
func main() {
var p = packet{}
p.a = 1
p.b = []byte("foo\x00\x00")
buf := bytes.Buffer{}
err := binary.Write(&buf, binary.BigEndian, p.a)
if err != nil {
fmt.Println(err)
}
_, err = buf.Write(p.b)
if err != nil {
fmt.Println(err)
}
h := sha256.New()
h.Write(buf.Bytes())
hash := h.Sum([]byte{})
fmt.Printf("% x\n", hash)
}
你是对的,使用encoding/binary在结构体中写入可能具有动态长度的项(切片和字符串)确实有些麻烦。你可能会对查看"encoding/gob"包感兴趣,它可以自动编码字符串(尽管它与你这里的填充字符串不兼容)。
英文:
Updated to something that works.
package main
import (
"bytes"
"crypto/sha256"
"encoding/binary"
"fmt"
)
type packet struct {
a uint8
b []byte
}
func main() {
var p = packet{}
p.a = 1
p.b = []byte("foo\x00\x00")
buf := bytes.Buffer{}
err := binary.Write(&buf, binary.BigEndian, p.a)
if err != nil {
fmt.Println(err)
}
_, err = buf.Write(p.b)
if err != nil {
fmt.Println(err)
}
h := sha256.New()
h.Write(buf.Bytes())
hash := h.Sum([]byte{})
fmt.Printf("% x\n", hash)
}
http://play.golang.org/p/t8ltu_WCpe
You're right that it's a bit painful to write structs with possibly dynamic length items in them (slices and strings) using encoding/binary. You might be interested in checking out the "encoding/gob" package that encodes strings automatically (although it isn't compatible with the padded string you've got here).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论