Cannot return []byte in cgo

I’m trying to create a DLL in Go for protection of royalty-free content via cryptography so users of a product I’m making in C++ can’t modify the content or steel it. I’m doing this because encryption and decryption in Go is (IMO) far less dangerous than it is in C++, and I feel more comfortable writing this part in Go than I do in C++. (And by dangerous, I don’t mean security wise, but considering that I don’t use pointers anywhere in my go code, far less dangerous in the memory department than it would be in C++). And no, I’m not writing my own crypto library, either – just writing functions to use to go crypto functions already there.
The encryption works. What doesn’t is the decryption. Whenever I run a decryption cycle in a test C++ app, it panics:
panic: runtime error: cgo result has Go pointer

goroutine 17 [running, locked to thread]:
main._cgoexpwrap_2edcd036b113_LoadRFMusic.func1(0xc000041ea0)
_cgo_gotypes.go:59 +0x75
main._cgoexpwrap_2edcd036b113_LoadRFMusic(0x4e7f75fbf0, 0xc, 0xc00165c000, 0x1593742, 0x1593742)
_cgo_gotypes.go:61 +0x96

I’ve pasted some of my decryption code (though not all of it for obvious reasons). LoadRFMusic() is supposed to return a go slice ([]byte). Something in Cgo doesn’t like that, apparently…
Here it is:

//export LoadRFMusic
func LoadRFMusic(file string) []byte {
    // Check to make sure input file exists. Redundant, but good in case ioutil misses something.
    if _, err := os.Stat(file); err==nil {
        message, err := ioutil.ReadFile(file)
        if err != nil {
            return nil
        }
        if len(message) <= NonceSize+15 {
            return nil
        }
        // Determine canary identifier and make sure it matches the right one.
        // Unnecessary for GCM, but I do it anyway. :)
        idReader:=bytes.NewReader(message[:15])
        id, err := binary.ReadUvarint(idReader)
        if err!=nil {
            return nil
        }
        if id!=/*...*/ {
            return nil
        }
        // set up GCM cipher, determine nonce, and decrypt. (Other code omitted.)
        out, err := gcm.Open(nil, nonce, message[15+NonceSize:], aad)
        if err != nil {
            return nil
        }
        return out
    } else {
        return nil
    }
}

Does anyone have any ideas of what’s going on?

How are you interfacing this with your C++ application? Is there a wrapper?

You’re not returning any cgo types, your function is only working with and returning Go types.

I’m loading it as a DLL dynamically:

// typedefs
// Other go types defined before this one...
typedef GoUint64 (*f_SaveRFMusic)(GoString, GoString);
typedef GoSlice(*f_LoadRFMusic) (GoString);
// in main...
// replaced all the macros for windows, linux and unix detection with WINDOWS, LINUX and UNIX for easier reading
#ifdef WINDOWS
HMODULE crfc = LoadLibrary("crfc.dll");
if (!crfc) {
cout << "DLL load error" << endl;
return 1;
}
f_SaveRFMusic SaveRFMusic = (f_SaveRFMusic)GetProcAddress(crfc, "SaveRFMusic");
f_LoadRFMusic LoadRFMusic = (f_LoadRFMusic)GetProcAddress(crfc, "LoadRFMusic");
#elif LINUX||UNIX
void *crfc = dlopen("./libcrfc.so", RTLD_NOW);
if (!crfc) {
cout << "SO load error" << endl;
return 1;
}
f_SaveRFMusic SaveRFMusic = dlsym(crfc, "SaveRFMusic");
f_LoadRFMusic LoadRFMusic = dlsym(crfc, "LoadRFMusic");
#endif

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