0

I am trying to use a function from a C library in python using ctypes. The called function calculates a SHA256 hash output from the input of fixed length 38 and a given state of the hash function.

The problem now is, that I get different results calling the function with python and calling it within a C program. Is there a difference in encoding of uint8 of C and byte-array strings from python? Or am I missing something else?

Here the function call in C:

uint8_t input[38] = {"0"};
uint8_t state[40] = {"0"};
uint8_t output[32] = {"0"};

sha256_inc_finalize(output, state, input, 38);

And the function call in python (3.10.4):

import ctypes

sha = ctypes.CDLL('/path/to/lib/sha_lib.so')
func = sha.sha256_inc_finalize

func.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_size_t]    

out = ctypes.create_string_buffer(b'00000000000000000000000000000000', size=32)
state = ctypes.create_string_buffer(b'0000000000000000000000000000000000000000', size=40) 
input = b'00000000000000000000000000000000000000'
func(out, state, input, 38)

I do not include the value of output after the call of sha256_inc_finalize here because it is just a hash value.

Any clue on what's going on here is much appreciated!

EDIT:

The hash of the function called from C is

3ca2f9f4 37712b50 7b046090 4497276a 81199415 1a7760a3 60840c92 747c8bbe

while the call via python outputs:

133cc1c1 4a8bd095 37e022d1 829a2261 1a0aab38 35a0c2ab 291a088e bb2d1c82

MrVanC
  • 1
  • 3
  • What's the signature of *sha256\_inc\_finalize*? – CristiFati Sep 27 '22 at 13:05
  • I edited my question and added the hash output of the function – MrVanC Sep 27 '22 at 13:59
  • Your Python code is passing data consisting of all zero bytes. Your C code is passing data that starts with an ASCII zero character, which is 0x30. – jasonharper Sep 27 '22 at 14:04
  • I asked for the function (*C*) **signature**. Is this the function? https://github.com/mupq/mupq/blob/master/common/sha2.h? – CristiFati Sep 27 '22 at 14:16
  • Sorry @CristiFati i misunderstood. No it is part of the Sphincs+ implementation which is different from standard sha256 https://github.com/sphincs/sphincsplus/blob/master/ref/sha2.c – MrVanC Sep 27 '22 at 14:20
  • @jasonharper but printing the hex version of my python input also gives me the ASCII zero of 0x30 and in reverse initializing the C variables with 0 instead of "0" also doesn't solve the problem – MrVanC Sep 27 '22 at 14:22
  • In the C code only the first byte is ASCII zero and the rest are value zero. In the Python code all the bytes are ASCII zero. – Mark Tolonen Sep 27 '22 at 18:49

1 Answers1

0

Although not the case here, [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer).

You claim you got some results but you didn't show how (AFAIC those pieces of code could be buggy and also the source of the problem).

Anyway, in order to create a MCVE ([SO]: How to create a Minimal, Reproducible Example (reprex (mcve))), I had to build a couple of files from [GitHub]: sphincs/spincsplus - sphincsplus in order to get a libsha2.so that I could work with.

code00.py:

#!/usr/bin/env python

import ctypes as cts
import sys


DLL_NAME = "/mnt/e/Work/Dev/GitHub/CristiFati/sphincsplus/libsha2.{:s}".format("dll" if sys.platform[:3].lower() == "win" else "so")
BytePtr = cts.POINTER(cts.c_ubyte)


def hex_dump(arr, group=4, text=""):
    print("\n{:s}".format(text if text else ""))
    print(arr)
    pat = "{:02X}" * group
    cnt, last = divmod(len(arr), group)
    for i in range(cnt):
        print(pat.format(*arr[i * group:(i + 1) * group]), end=" ")
    print(("{:02X}" * last).format(*arr[cnt * group:]))


def main(*argv):
    dll = cts.CDLL(DLL_NAME)
    sha256_inc_finalize = dll.sha256_inc_finalize
    sha256_inc_finalize.argtypes = (BytePtr, BytePtr, BytePtr, cts.c_size_t)
    sha256_inc_finalize.restype = None

    inp_len = 38
    inp = b"0" * inp_len
    #inp = b"0" + b"\x00" * (inp_len - 1)
    outp_len = 32
    outp = cts.create_string_buffer(outp_len)
    state_len = 40
    state = cts.create_string_buffer(state_len)
    sha256_inc_finalize(cts.cast(outp, BytePtr), cts.cast(state, BytePtr), cts.cast(inp, BytePtr), inp_len)
    hex_dump(inp, text="input:")
    hex_dump(state, text="state:")
    hex_dump(outp, text="output:")


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.\n")
    sys.exit(rc)

Output:

(qaic-env) [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q073866657]> python code00.py
Python 3.8.10 (default, Jun 22 2022, 20:18:18) [GCC 9.4.0] 064bit on linux


input:
b'00000000000000000000000000000000000000'
30303030 30303030 30303030 30303030 30303030 30303030 30303030 30303030 30303030 3030

state:
<ctypes.c_char_Array_40 object at 0x7fe69dde58c0>
51B8117D 8B54D933 939F51DA E3798764 07FAB6C2 31CFF0B8 F3F2CD3E 9903EC84 00000000 00000000

output:
<ctypes.c_char_Array_32 object at 0x7fe69dd069c0>
51B8117D 8B54D933 939F51DA E3798764 07FAB6C2 31CFF0B8 F3F2CD3E 9903EC84

Done.
CristiFati
  • 38,250
  • 9
  • 50
  • 87