1

For our C/C++ app we are using Security Transforms API for doing some basic encryption/decryption.
And now we need to calculate hash (especially SHA256) of data, and though documentation claims that Security Transforms also provides a way of hashing, but seems there is no details of how to do it. And seems google doesn't bring any example or details on it as well.
So question is:
Is it really possible to calculate hash (SHA256 if possible) using Security Transforms?
And if no, then is there any other API (provided by Apple) to calculate it using C/C++?

Just Shadow
  • 10,860
  • 6
  • 57
  • 75
  • 1
    Downvoter, could you please clarify the reason of downvoting, to make it easier to improve the question? – Just Shadow Feb 21 '18 at 08:07
  • Possible duplicate of [Generate SHA256 hash in Objective-C](https://stackoverflow.com/questions/16866001/generate-sha256-hash-in-objective-c) – jww Feb 22 '18 at 03:35
  • 1
    @jww Thanks for note, but that's slightly different question, as it's about using objective c, but here we need solution on c++, as well as with Security Transforms if possible – Just Shadow Feb 22 '18 at 04:47

2 Answers2

4

I don't know about Security Transforms. You can use Apple's CommonCrypto library for this, though.

Oddly much of CommonCrypto does not seem to be well documented (at least that I can find), but in https://opensource.apple.com//source/CommonCrypto/CommonCrypto-7/CommonCrypto/CommonDigest.h.auto.html find the following declarations:

extern int CC_SHA256_Init(CC_SHA256_CTX *c);
extern int CC_SHA256_Update(CC_SHA256_CTX *c, const void *data, CC_LONG len);
extern int CC_SHA256_Final(unsigned char *md, CC_SHA256_CTX *c);
Jack Lloyd
  • 8,215
  • 2
  • 37
  • 47
0

After digging a lot it turned out that it's possible with Security Transforms API though it was not documented. To make it work, crafted samples of AES encryption with SecDigestTransformCreate and used list of available hashing algorithms there.

Here is a C and C++ friendly solution:

#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>

#ifdef __cplusplus
#include <vector>
#else // C
#include <stdbool.h> // For adding boolean support
#endif // __cplusplus

// Convenience define for cleanup
#define _CLEANUP_IF(a) if ((a)) goto Cleanup;

#ifdef __cplusplus
// Wrap into class in case of C++

class Sha256Calculator {
public:
#endif // __cplusplus

    // Calculates SHA256 hash from given array of data and returns array
    // Note: Parameter "outHash" is manually allocated so consider calling free(outHash) after using it
    static bool calculateSha256(uint8_t** outHash, size_t* outHashSize, const uint8_t *data, const size_t dataSize)
    {
        bool result = false;
        CFErrorRef error = NULL;

        SecTransformRef digestTransform = NULL;

        CFDataRef sourceData = NULL;
        CFDataRef outDataRef = NULL;
        const UInt8 * outData = NULL;
        CFIndex outDataSize = 0;


        // Create a CFData object from the source
        sourceData = CFDataCreate(kCFAllocatorDefault, (const UInt8*)data, dataSize);
        _CLEANUP_IF(!sourceData);

        digestTransform = SecDigestTransformCreate(kSecDigestSHA2, 256, &error);
        _CLEANUP_IF(error);

        SecTransformSetAttribute(digestTransform, kSecTransformInputAttributeName, (CFDataRef)sourceData, &error);
        _CLEANUP_IF(error);

        outDataRef = (CFDataRef)SecTransformExecute(digestTransform, &error);
        _CLEANUP_IF(error);
        _CLEANUP_IF(!outDataRef);


        // Extract data from CFDataRef to array
        outData = CFDataGetBytePtr(outDataRef);     // Returns read-only (UInt8*) pointer to the data
        outDataSize = CFDataGetLength(outDataRef);


        if (outHash) {
            *outHash = (uint8_t*)malloc(outDataSize);
            if (*outHash) {
                memcpy(*outHash, outData, outDataSize);
                if (outHashSize) {
                    *outHashSize = (size_t)outDataSize;
                }
                result = true;
            }
        }

        // Notes:
        //   * All the objects are released except "outData" since it's handled and cleaned by using outDataRef
        //   * CFRelease throws error if the passed object is NULL, so check objects before releasing

    Cleanup:
        // Use CFShow(error) for getting details about error
        if (error) { CFRelease(error); }
        if (digestTransform) { CFRelease(digestTransform); }
        if (sourceData) { CFRelease(sourceData); }
        if (outDataRef) { CFRelease(outDataRef); }

        return result;
    }

#ifdef __cplusplus
    // Convenience method for cpp using vectors
    static bool calculateSha256(std::vector<uint8_t>& outHash, const std::vector<uint8_t>& data)
    {
        // Call original method
        uint8_t * outHashArray = nullptr;
        size_t outHashSize;
        bool result;
        result = calculateSha256(&outHashArray, &outHashSize, data.data(), data.size());
        if (!result)
            return false;

        // Put resulting array in vector
        outHash.clear();
        outHash.insert(outHash.end(), &outHashArray[0], &outHashArray[outHashSize]);

        // Clean allocated array
        if (outHashArray)
            free(outHashArray);

        return result;
    }
};
#endif // __cplusplus

Note:
In order to use any other hashing algorithgm instead of SHA256 feel free to modify the line:
SecDigestTransformCreate(kSecDigestSHA2, 256, &error);
with desired available hashing algorithm name and appropriate length.

PS Hope, Apple will guys will update their documentation...

Just Shadow
  • 10,860
  • 6
  • 57
  • 75