使用 OS 提供的 API 在 MacOS 上散列
Hashing on MacOS using API provided by OS
对于我们的 C/C++ 应用程序,我们使用 Security Transforms API 来做一些基本的 encryption/decryption。
而现在我们需要计算数据的哈希(尤其是 SHA256),虽然文档声称 Security Transforms 也提供了一种哈希的方法,但似乎没有详细说明如何做。而且似乎 google 也没有提供任何示例或详细信息。
所以问题是:
是否真的可以使用安全转换来计算哈希值(如果可能的话是 SHA256)?
如果没有,那么是否还有其他 API(由 Apple 提供)使用 C/C++ 计算它?
我不知道安全转换。不过,您可以为此使用 Apple 的 CommonCrypto 库。
奇怪的是,CommonCrypto 的大部分内容似乎都没有很好的文档记录(至少我能找到),但在 https://opensource.apple.com//source/CommonCrypto/CommonCrypto-7/CommonCrypto/CommonDigest.h.auto.html 中找到以下声明:
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);
经过大量挖掘后发现 可能 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。
这是一个 C 和 C++ 友好的解决方案:
#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
注:
为了使用 任何其他 哈希算法而不是 SHA256,请随意修改行:
SecDigestTransformCreate(kSecDigestSHA2, 256, &error);
具有所需的可用哈希算法 name 和适当的长度。
PS 希望 Apple 会更新他们的文档...
对于我们的 C/C++ 应用程序,我们使用 Security Transforms API 来做一些基本的 encryption/decryption。
而现在我们需要计算数据的哈希(尤其是 SHA256),虽然文档声称 Security Transforms 也提供了一种哈希的方法,但似乎没有详细说明如何做。而且似乎 google 也没有提供任何示例或详细信息。
所以问题是:
是否真的可以使用安全转换来计算哈希值(如果可能的话是 SHA256)?
如果没有,那么是否还有其他 API(由 Apple 提供)使用 C/C++ 计算它?
我不知道安全转换。不过,您可以为此使用 Apple 的 CommonCrypto 库。
奇怪的是,CommonCrypto 的大部分内容似乎都没有很好的文档记录(至少我能找到),但在 https://opensource.apple.com//source/CommonCrypto/CommonCrypto-7/CommonCrypto/CommonDigest.h.auto.html 中找到以下声明:
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);
经过大量挖掘后发现 可能 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。
这是一个 C 和 C++ 友好的解决方案:
#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
注:
为了使用 任何其他 哈希算法而不是 SHA256,请随意修改行:
SecDigestTransformCreate(kSecDigestSHA2, 256, &error);
具有所需的可用哈希算法 name 和适当的长度。
PS 希望 Apple 会更新他们的文档...