2

I am attempting to build a (very simple) Python extension from C code and have run into a snag in the compilation.

(For the record: my C skills are very out-of-date and my code is probably awful.)

As directed in the docs and on another site I found, I created a C file that exposes the functionality I need built into a Python module:

#include "strcrypto.h"
#include <stdlib.h>

#define CRYPTO_POOLNUMBER 15

int main() {
    return 0;
}

char* encryptString(char* string) {
    COMM* comm;
    char* encrypted_string = malloc(sizeof(char) * 4096);
    int res;

    comm = init_client(CRYPTO_PORT);

    if (comm == NULL) {
        return NULL;
    }

    res = StrEncrypt(comm, string, encrypted_string, CRYPTO_POOLNUMBER);

    end_client(comm);
    if (res != 1) {
        return NULL;
    }
    else {
        return encrypted_string;
    }
}

char* decrypt(char* string) {
    COMM* comm;
    char* decrypted_string = malloc(sizeof(char) * 4096);
    int res;

    comm = init_client(CRYPTO_PORT);

    if (comm == NULL) {
        return NULL;
    }

    res = StrDecrypt(comm, string, decrypted_string);

    end_client(comm);
    if (res != 1) {
        return NULL;
    }
    else {
        return decrypted_string;
    }
}

char* randomToken(char* string) {
    COMM* comm;
    char* token = malloc(sizeof(char) * 4096);
    int res;

    comm = init_client(CRYPTO_PORT);

    if (comm == NULL) {
        return NULL;
    }

    res = getPBToken(comm, string, token);

    end_client(comm);
    if (res != 1) {
        return NULL;
    }
    else {
        return token;
    }
}

char* fixedToken(char* string) {
    COMM* comm;
    char* token = malloc(sizeof(char) * 4096);
    int res;

    comm = init_client(CRYPTO_PORT);

    if (comm == NULL) {
        return NULL;
    }

    res = getFixedToken(comm, string, token);

    end_client(comm);
    if (res != 1) {
        return NULL;
    }
    else {
        return token;
    }
}

I also created the C file that wraps the methods for Python:

#include <Python.h>

static PyObject* crypto_encrypt(PyObject* self, PyObject* args) {
    char* original_string;
    char* encrypted_string;
    PyObject* return_value;

    if (!PyArg_ParseTuple(args, "s", &original_string)) {
        return NULL;    // Could not parse string or no string was passed.
    }

    encrypted_string = encryptString(original_string);

    if (encrypted_string == NULL) {
        return NULL;
    }
    else {
        return_value = PyString_FromString(encrypted_string);
        free(encrypted_string);
        return return_value;
    }
}

static PyObject* crypto_decrypt(PyObject* self, PyObject* args) {
    char* original_string;
    char* decrypted_string;
    PyObject* return_value;

    if (!PyArg_ParseTuple(args, "s", &original_string)) {
        return NULL;    // Could not parse string or no string was passed.
    }

    decrypted_string = decryptString(original_string);

    if (decrypted_string == NULL) {
        return NULL;
    }
    else {
        return_value = PyString_FromString(decrypted_string);
        free(decrypted_string);
        return return_value;
    }
}

static PyObject* crypto_fixedToken(PyObject* self, PyObject* args) {
    char* original_string;
    char* token;
    PyObject* return_value;

    if (!PyArg_ParseTuple(args, "s", &original_string)) {
        return NULL;    // Could not parse string or no string was passed.
    }

    token = fixedToken(original_string);

    if (token == NULL) {
        return NULL;
    }
    else {
        return_value = PyString_FromString(token);
        free(token);
        return return_value;
    }
}

static PyObject* crypto_randomToken(PyObject* self, PyObject* args) {
    char* original_string;
    char* token;
    PyObject* return_value;

    if (!PyArg_ParseTuple(args, "s", &original_string)) {
        return NULL;    // Could not parse string or no string was passed.
    }

    token = randomToken(original_string);

    if (token == NULL) {
        return NULL;
    }
    else {
        return_value = PyString_FromString(token);
        free(token);
        return return_value;
    }
}

static PyMethodDef CryptoMethods[] = {
    { "encrypt", crypto_encrypt, METH_VARARGS, "Encrypt text using a Crypto server." },
    { "decrypt", crypto_decrypt, METH_VARARGS, "Decrypt text encrypted using a Crypto server." },
    { "getFixedToken", crypto_fixedToken, METH_VARARGS, "Return a fixed PKCS5 token from Crypto." },
    { "getRandomToken", crypto_randomToken, METH_VARARGS, "Return a random PKCS5 token from Crypto." },
    { NULL, NULL, 0, NULL }
};

PyMODINIT_FUNC initcrypto(void) {
    (void) Py_InitModule("crypto", CryptoMethods);
}

Finally, I created a setup.py file that creates the extension and calls setup() on the extension:

from distutils.core import setup, Extension

ext = Extension("crypto",
    ["cryptomodule.c", "crypto.c"],
    libraries = ["strcrypto",],
    library_dirs = ["/usr/local/lib",]
)

setup(name = "crypto", ext_modules = [ext,])

The library "strcrypto" is actually "libstrcrypto.a" and was provided to me; it wasn't something I wrote. Unfortunately, that is also what appears to be causing the error when I go to install the file:

running install
running build
running build_ext
building 'crypto' extension
x86_64-linux-gnu-gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c cryptomodule.c -o build/temp.linux-x86_64-2.7/cryptomodule.o
cryptomodule.c: In function ‘crypto_encrypt’:
cryptomodule.c:15:5: warning: implicit declaration of function ‘encryptString’ [-Wimplicit-function-declaration]
     encrypted_string = encryptString(original_string);
     ^
cryptomodule.c:15:22: warning: assignment makes pointer from integer without a cast [enabled by default]
     encrypted_string = encryptString(original_string);
                      ^
cryptomodule.c: In function ‘crypto_decrypt’:
cryptomodule.c:36:5: warning: implicit declaration of function ‘decryptString’ [-Wimplicit-function-declaration]
     decrypted_string = decryptString(original_string);
     ^
cryptomodule.c:36:22: warning: assignment makes pointer from integer without a cast [enabled by default]
     decrypted_string = decryptString(original_string);
                      ^
cryptomodule.c: In function ‘crypto_fixedToken’:
cryptomodule.c:57:5: warning: implicit declaration of function ‘fixedToken’ [-Wimplicit-function-declaration]
     token = fixedToken(original_string);
     ^
cryptomodule.c:57:11: warning: assignment makes pointer from integer without a cast [enabled by default]
     token = fixedToken(original_string);
           ^
cryptomodule.c: In function ‘crypto_randomToken’:
cryptomodule.c:78:5: warning: implicit declaration of function ‘randomToken’ [-Wimplicit-function-declaration]
     token = randomToken(original_string);
     ^
cryptomodule.c:78:11: warning: assignment makes pointer from integer without a cast [enabled by default]
     token = randomToken(original_string);
           ^
x86_64-linux-gnu-gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c crypto.c -o build/temp.linux-x86_64-2.7/crypto.o
crypto.c:6:5: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
 int main() {
     ^
x86_64-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -D_FORTIFY_SOURCE=2 -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security build/temp.linux-x86_64-2.7/cryptomodule.o build/temp.linux-x86_64-2.7/crypto.o -L/usr/local/lib -lstrcrypto -o build/lib.linux-x86_64-2.7/crypto.so
/usr/bin/ld: /usr/local/lib/libstrcrypto.a(strcrypto.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
/usr/local/lib/libstrcrypto.a: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

I don't know what that error means, because as you can see, the gcc calls are indeed using -fPIC.

Can someone please point out what I'm doing wrong here? Thanks in advance.

1 Answer 1

1

The Python extension you are building is a shared library. The code in a shared library

must be compiled to be position independent. This is done by compiling with -fPIC.

Your problem is that your libstrcrypto.a is not compiled with -fPIC and therefore cannot be used inside a shared library. You have several alternatives:

  1. Ask for a version of libstrcrypto.a that is compiled with -fPIC.
  2. Ask for a shared library version of libstrcrypto.a.
  3. Link your extension statically to produce a new Python executable that contains your extension built in.
  4. Split the extension into an executable that links with the library and a python extension that somehow communicates with the executable.
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the reply. My coworker has to go back to the vendor and ask about the version of strcrypto that is compiled with -fPIC. In the event that he's unable to do so, what are my options on getting the strcrypto library to work in Python?
Nevermind, the vendor delivered the updated module. Thanks again for your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.