Call shared library from python

I am trying to create shared library on golang, but when you call the library from python get an error.

Go code

package main

import (
"C"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
"io/ioutil"
)

var key = []byte("1251229395365605")

func encrypt(data []byte) ([]byte, string) {
block, err := aes.NewCipher(key)
if err != nil {
return make([]byte, 0), err.Error()
}

cipherdata := make([]byte, aes.BlockSize+len(data))
iv := cipherdata[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}

stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(cipherdata[aes.BlockSize:], data)

return cipherdata, ""
}

func decrypt(encryptedData []byte) ([]byte, string) {
block, err := aes.NewCipher(key)
if err != nil {
return make([]byte, 0), err.Error()
}

if len(encryptedData) < aes.BlockSize {
panic("ciphertext too short")
}
iv := encryptedData[:aes.BlockSize]
encryptedData = encryptedData[aes.BlockSize:]

stream := cipher.NewCFBDecrypter(block, iv)

stream.XORKeyStream(encryptedData, encryptedData)
return encryptedData, ""
}

//export encryptFile
func encryptFile(inpPath, outPath string) (string, string) {
file, err := ioutil.ReadFile(inpPath)
if err != nil{
return "error", err.Error()
}
cryptFile, _ := encrypt(file)
ioutil.WriteFile(outPath, cryptFile, 0755)
return "ok", ""
}

//export decryptFile
func decryptFile(inpPath, outPath string) (string, string) {
file, err := ioutil.ReadFile(inpPath)
if err != nil{
return "error", err.Error()
}
origFile, _ := decrypt(file)
ioutil.WriteFile(outPath, origFile, 0755)
return "ok", ""
}

func main() {
}

Code for causing a compiled library

    from ctypes import cdll

    crypter = cdll.LoadLibrary('./crypter.so')
    crypter.encryptFile('./images.jpg', './crypt-images.jpg')
    crypter.decryptFile('./crypt-images.jpg', './original-images.jpg')

As a result, I getting this error

> unexpected fault address 0x7fbd27000000
> fatal error: fault
> [signal SIGSEGV: segmentation violation code=0x1 addr=0x7fbd27000000 pc=0x104a47850]

> goroutine 17 [running, locked to thread]:
> runtime.throw(0x104aac2cd, 0x5)
> /usr/local/Cellar/go/1.7.3/libexec/src/runtime/panic.go:566 +0x95 fp=0xc42003cc08 sp=0xc42003cbe8
> runtime.sigpanic()
> /usr/local/Cellar/go/1.7.3/libexec/src/runtime/sigpanic_unix.go:27 +0x288 fp=0xc42003cc60 sp=0xc42003cc08
> runtime.memmove(0xc42009a005, 0x7fbd24d14960, 0x102d38000)
> /usr/local/Cellar/go/1.7.3/libexec/src/runtime/memmove_amd64.s:92 +0xa0 fp=0xc42003cc68 sp=0xc42003cc60
> runtime.concatstrings(0x0, 0xc42003cd50, 0x5, 0x5, 0xc420000680, 0x0)
> /usr/local/Cellar/go/1.7.3/libexec/src/runtime/string.go:52 +0x1a4 fp=0xc42003cd08 sp=0xc42003cc68
> runtime.concatstring5(0x0, 0x104aac18d, 0x4, 0x104aabf90, 0x1, 0x7fbd24d14960, 0x102d38000, 0x104aabfc1, 0x2, 0x104aad7b0, ...)
> /usr/local/Cellar/go/1.7.3/libexec/src/runtime/string.go:71 +0x47 fp=0xc42003cd48 sp=0xc42003cd08
> os.(*PathError).Error(0xc4200162a0, 0x102d38000, 0x0)
> /usr/local/Cellar/go/1.7.3/libexec/src/os/error.go:26 +0xab fp=0xc42003cdc0 sp=0xc42003cd48
> main.encryptFile(0x7fbd24d14960, 0x102d38000, 0x5, 0x102d3ba00, 0xc420084000, 0x0, 0xc42003cea0, 0x104a1b293)
> /Users/alex/Golang/src/protectioninf/lab4/lab4.go:57 +0x61 fp=0xc42003ce10 sp=0xc42003cdc0
> main._cgoexpwrap_63570e3f2397_encryptFile(0x7fbd24d14960, 0x102d38000, 0x5, 0x102d3ba00, 0x0, 0x0, 0x0, 0x0)
> command-line-arguments/_obj/_cgo_gotypes.go:49 +0xbf fp=0xc42003ce60 sp=0xc42003ce10
> runtime.call64(0x0, 0x7fff5d104018, 0x7fff5d1040d8, 0x40)
> /usr/local/Cellar/go/1.7.3/libexec/src/runtime/asm_amd64.s:480 +0x4c fp=0xc42003ceb0 sp=0xc42003ce60
> runtime.cgocallbackg1(0x0)
> /usr/local/Cellar/go/1.7.3/libexec/src/runtime/cgocall.go:283 +0x19d fp=0xc42003cf28 sp=0xc42003ceb0
> runtime.cgocallbackg(0x0)
> /usr/local/Cellar/go/1.7.3/libexec/src/runtime/cgocall.go:170 +0x84 fp=0xc42003cf90 sp=0xc42003cf28
> runtime.cgocallback_gofunc(0x0, 0x0, 0x0, 0x0)
> /usr/local/Cellar/go/1.7.3/libexec/src/runtime/asm_amd64.s:728 +0x74 fp=0xc42003cfb0 sp=0xc42003cf90
> runtime.goexit()
> /usr/local/Cellar/go/1.7.3/libexec/src/runtime/asm_amd64.s:2086 +0x1 fp=0xc42003cfb8 sp=0xc42003cfb0

> goroutine 18 [syscall, locked to thread]:
> runtime.goexit()
> /usr/local/Cellar/go/1.7.3/libexec/src/runtime/asm_amd64.s:2086 +0x1

I guess the problem is that C strings are different from Go strings. (C strings are terminated with a null character whereas Go strings store their length in a header struct.

According to the section C references to Go and the code block directly above (!) that section, there are functions available to convert C strings to Go strings (C.GoString and C.GoStringN), and back (C.CString), and a returned string is a *C.char rather than a string.

I must say I have not used a Go shared library from C myself yet (let alone from Python), so there might be more to it than the above. There is a quite extensive blog article that walks through a complete example of calling Go code from Python.

you may also have a look at gopy and this blog post on the gopher academy from last year:
https://blog.gopheracademy.com/advent-2015/gopy/

</shamelessplug>

hth,
-s

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.