Search code examples
cswifthashc-stringsargon2-ffi

How to convert hex string to CString in Swift?


I'm new to swift and i need to convert a hex string in swift to a CString to use in argon2 binding in c.

I have seen:

let saltCString = context.salt.cString(using: .utf8)

argon2id_hash_raw(UInt32(context.iterations), UInt32(context.memory), UInt32(context.parallelism), passwordCString,
                                          passwordLength, saltCString, saltLength, &hashResult, hashLength)

But I want to pass a key instead of passpharse, does it work if I pass a salt of hex string and change .utf8 to .hex?


Solution

  • argon2id_hash_raw does not expect a C string (terminated with NUL byte), but a uint8_t array. Therefore the length is a separate parameter, see https://github.com/P-H-C/phc-winner-argon2/blob/master/src/argon2.c lines 136 - 137:

    context.salt = CONST_CAST(uint8_t *)salt;
    context.saltlen = (uint32_t)saltlen;
    

    Since you have a hexadecimal encoded string in Swift, you can convert it to a UInt8 array using this nice answer https://stackoverflow.com/a/43360864.

    Test

    If we define a small C function just to test the conversion, it might look like this:

    #include <stdio.h>
    #include "some_cfile.h"
    
    void print_salt(const uint8_t *salt, uint32_t len) {
        for(uint32_t i = 0; i < len; i++) {
            printf("%x ", salt[i]);
        }
        printf("\n");
    }
    

    For the sake of completeness, the test header file would then look like this:

    #ifndef some_cfile_h
    #define some_cfile_h
    
    #include <inttypes.h>
    
    void print_salt(const uint8_t *salt, uint32_t len);
    
    #endif /* some_cfile_h */
    

    From Swift side this would then be called as follows:

    struct Context {
        let salt: String
    }
    ...
    let context = Context(salt: "687568")
    ...
    let salt = context.salt.hexaBytes
    print_salt(salt, UInt32(salt.count))
    

    This test finally gives the expected output:

    68 75 68