I am doing a file uploading job. I want to generate SHA256 and CRC32 hashes. Can anyone help me how shall I generate those hash? I want to get it working for iOS.
SHA256 is available in CommonCrypto. CRC32 is not a hash, it a Cyclic Redundancy Check.
Example code:
#import <CommonCrypto/CommonDigest.h>
NSData *dataIn = [#"Now is the time for all good computers to come to the aid of their masters." dataUsingEncoding:NSASCIIStringEncoding];
NSMutableData *macOut = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
CC_SHA256(dataIn.bytes, dataIn.length, macOut.mutableBytes);
NSLog(#"dataIn: %#", dataIn);
NSLog(#"macOut: %#", macOut);
NSLog output:
dataIn: <4e6f7720 69732074 68652074 696d6520 666f7220 616c6c20 676f6f64 20636f6d 70757465 72732074 6f20636f 6d652074 6f207468 65206169 64206f66 20746865 6972206d 61737465 72732e>
macOut: <53f89cf6 7ebfbe56 89f1f76a 3843dfd1 09d68c5b a938dcd2 9a12004e 108260cb>
For both of these, you can use this gist:
https://gist.github.com/paul-delange/6808278
And an example
NSString* crc32 = (__bridge NSString*)TGDFileHashCreateWithPath((__bridge CFStringRef)filepath, TGDFileHashDefaultChunkSizeForReadingData, TGDChecksumAlgorithmCRC32);
This method will generate crc32c as used by gcloud on iOS from a filepath. If you want the standard crc32 just uncomment the other value for CRC32_POLYNOMIAL.
It reads the file given in 512KB chunks so can be used on large files.
- (NSString*) crc32c:(NSString*)filepath{
/// using crc code from
// http://classroomm.com/objective-c/index.php?action=printpage;topic=2891.0
// by rgronlie
//this is the standard crc32 polynomial
//uint32_t CRC32_POLYNOMIAL = 0xEDB88320;
//this is the crc32c one
uint32_t CRC32_POLYNOMIAL = 0x82F63B78L;
uint32_t CRC32C_SEED = 0xFFFFFFFFL;
// create and populate a lookup table
uint32_t* pCRCTable = malloc(sizeof(uint32_t) * 256);
for (uint32_t i = 0; i <= 255; i++)
{
uint32_t crc32 = i;
for (uint32_t j = 8; j > 0; j--)
{
if ((crc32 & 1) == 1)
crc32 = (crc32 >> 1) ^ CRC32_POLYNOMIAL;
else
crc32 >>= 1;
}
pCRCTable[i] = crc32;
}
// get a handle to the file
NSFileHandle *filehandle = [NSFileHandle fileHandleForReadingAtPath:filepath];
if(filehandle == NULL){
NSLog(#"failed to create file handle");
return nil;
}
// a buffer to read into
NSData* databuffer;
uint32_t crc = CRC32C_SEED;
// read the file in chunks of 512KB
while(true){
databuffer = [filehandle readDataOfLength: 512 * 1024];
// if there is nothing left finish
if([databuffer length] == 0){
break;
}
// otherwise run each chunk through the lookup table
uint8_t *pBytes = (uint8_t *)[databuffer bytes];
uint32_t length = [databuffer length];
while (length--)
{
crc = (crc>>8) ^ pCRCTable[(crc & 0xFF) ^ *pBytes++];
}
}
// clean up
[filehandle closeFile];
free(pCRCTable);
// this is the result
uint32_t hash = crc ^ 0xFFFFFFFFL;
// reverse it for endianness
uint32_t hash_reversed = CFSwapInt32HostToBig(hash);
// as raw bytes
NSData* hash_data = [NSData dataWithBytes: &hash_reversed length: sizeof(hash_reversed)];
// return base64 encoded
return [hash_data base64EncodedStringWithOptions:0];
}
there are no apps which can generate Hash for ios
This should work....its for Mac
http://itunes.apple.com/us/app/digiprint/id473233587?mt=12
Related
I am making a C program that supports many languages. The program send emails using the type WCHAR instead of char. The problem is that when I receive the email and read it, some characters are not shown correctly, even some English ones like e, m, ... This is an example:
<!-- language: lang-c -->
curl_easy_setopt(hnd, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(hnd, CURLOPT_READDATA, &upload_ctx);
static const WCHAR *payload_text[]={
L"To: <me#mail.com>\n",
L"From: <me#mail.com>(Example User)\n",
L"Subject: Hello!\n",
L"\n",
L"Message sent\n",
NULL
};
struct upload_status {
int lines_read;
};
static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp){
struct upload_status *upload_ctx = (struct upload_status *)userp;
const WCHAR *data;
if ((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
return 0;
}
data = payload_text[upload_ctx->lines_read];
if (data) {
size_t len = wcslen(data);
memcpy(ptr, data, len);
upload_ctx->lines_read ++;
return len;
}
return 0;
}
memcpy() operates on bytes, not on characters. You are not taking into account that sizeof(wchar_t) > 1. It is 2 bytes on some systems and 4 bytes on others. This descrepency makes wchar_t a bad choice when writing portable code. You should be using a Unicode library instead, such as icu or iconv).
You need to take sizeof(wchar_t) into account when calling memcpy(). You also need to take into account that the destination buffer may be smaller than the size of the text bytes you are trying to copy. Keeping track of the lines_read by itself is not enough, you have to also keep track of how many bytes of the current line you have copied so you can handle cases when the current line of text straddles across multiple destination buffers.
Try something more like this instead:
static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp)
{
struct upload_status *upload_ctx = (struct upload_status *) userp;
unsigned char *buf = (unsignd char *) ptr;
size_t available = (size * nmemb);
size_t total = 0;
while (available > 0)
{
wchar_t *data = payload_text[upload_ctx->lines_read];
if (!data) break;
unsigned char *rawdata = (unsigned char *) data;
size_t remaining = (wcslen(data) * sizeof(wchar_t)) - upload_ctx->line_bytes_read;
while ((remaining > 0) && (available > 0))
{
size_t bytes_to_copy = min(remaining, available);
memcpy(buf, rawdata, bytes_to_copy);
buf += bytes_to_copy;
available -= bytes_to_copy;
total = bytes_to_copy;
rawdata += bytes_to_copy;
remaining -= bytes_to_copy;
upload_ctx->line_bytes_read += bytes_to_copy;
}
if (remaining < 1)
{
upload_ctx->lines_read ++;
upload_ctx->line_bytes_read = 0;
}
}
return total;
}
I define a struct for the move
typedef struct {
MsgType msgType;
int newFallenStonesSize;
char *newFallenStones;
} MsgMove;
And send the data like this:
MsgMove message;
message.msgType = MsgTypeMove;
message.newFallenStones = (char *)malloc(nrNewFallenStones*sizeof(char));
for (int i=0; i<nrNewFallenStones; i++) {
message.newFallenStones[i]=newFallenStones[i];
}
message.newFallenStonesSize = nrNewFallenStones;
NSData *data = [NSData dataWithBytes:&message length:(2*sizeof(int)+message.newFallenStonesSize*sizeof(char))];
[[KKGameKitHelper sharedGameKitHelper] sendDataToAllPlayers:data reliable:YES];
the data is correct at the moment of sending, but when I receive it like this:
else if (msg->msgType == MsgTypeMove)
{
MsgMove *msgMove = (MsgMove *) [data bytes];
for (int i=0; i<msgMove->newFallenStonesSize; i++) {
NSLog(#"New Stone received:%i",msgMove->newFallenStones[i]);
}
}
The values have changed. For example 1, 6, 3 and I receive 76, 105 98.
Anyone knows why this is happening?
The main issue is that you are sending a pointer to your data over the network rather than the actual data. When you malloc space for message.newFallenStones it will be set to some apparently random location in memory that is not adjacent to your MsgMove structure. You then write your data in this other memory location. What you package up to transfer is the MsgMove structure (with a pointer to somewhere else in memory) plus whatever random bytes happens to immediately follow it in memory.
The typical way this is handled is to instead have your entire message be malloc'ed together and write the data into the end of it. More like:
typedef struct {
MsgType msgType;
int newFallenStonesSize;
char newFallenStones; // The first newFallenStones value
} MsgMove;
and then send with
MsgMove *message;
message = (MsgMove *)malloc(sizeof(MsgMove)+nrNewFallenStones-1);
message->msgType = MsgTypeMove;
message->newFallenStonesSize = nrNewFallenStones;
char *newStones = &MsgMove->newFallenStones;
for (int i=0; i<nrNewFallenStones; i++) {
newStones[i]=newFallenStones[i];
}
NSData *data = [NSData dataWithBytes:message length:(sizeof(MsgMove)+nrNewFallenStones-1)];
[[KKGameKitHelper sharedGameKitHelper] sendDataToAllPlayers:data reliable:YES];
I have a NSData object coming back from my server, it varies in its content but sticks to a particular structure.
I would like to know (hopfully with some example code) how to work though this object to get the data I need out of it.
the structure of the data objects inside the objects are like this
leading value (UInt16) - (tells me what section of the response it is)
Size of string (UInt32) or number - (UInt32)
String (not null terminated) i.e. followed by the next leading value.
I have been reading through the Binary Data Programming Guide however that's only really showing me how to put my data into new NSData objects and accessing and compairing the bytes.
The thing I am stuck on is how do I say grab the info dynamically. Check the NSdata objects first leading value figure out if its string or int then get the string or int and move onto the next leading value..
any suggestions or example code would be really helpfull.. just stuck in abit of a mind block as I have never attempted anything like this in objective C.
Some of this depends on how your server is written to encode the data into what it is sending you. Assuming it is encoding the numeric values using standard network byte ordering (big-endian) you will want it converted to the correct byte-ordering for iOS (I believe that is always little-endian).
I would approach it something like this:
uint16_t typeWithNetworkOrdering, typeWithLocalOrdering;
uint32_t sizeWithNetworkOrdering, sizeWithLocalOrdering;
char *cstring = NULL;
uint32_t numberWithNetworkOrdering, numberWithLocalOrdering;
const void *bytes = [myData bytes];
NSUInteger length = [myData length];
while (length > 0) {
memcpy(&typeWithNetworkOrdering, bytes, sizeof(uint16_t));
bytes += sizeof(uint16_t);
length -= sizeof(uint16_t);
memcpy(&sizeWithNetworkOrdering, bytes, sizeof(uint32_t));
bytes += sizeof(uint32_t);
length -= sizeof(uint32_t);
typeWithLocalOrdering = CFSwapInt16BigToHost(typeWithNetworkOrdering);
sizeWithLocalOrdering = CFSwapInt32BigToHost(sizeWithNetworkOrdering);
if (typeWithLocalOrdering == STRING_TYPE) { // STRING_TYPE is whatever type value corresponds to a string
cstring = (char *) malloc(sizeWithLocalOrdering + 1);
strncpy(cstring, bytes, sizeWithLocalOrdering);
cstring[sizeWithLocalOrdering] = '\0';
NSString *resultString = [NSString stringWithCString:cstring encoding:NSUTF8StringEncoding];
NSLog(#"String = %#", resultString);
free(cstring);
bytes += sizeWithLocalOrdering;
length -= sizeWithLocalOrdering;
// Do whatever you need to with the string
}
else if (typeWithLocalOrdering == NUMBER_TYPE) { // NUMBER_TYPE is whatever type value corresponds to a number
memcpy(&numberWithNetworkOrdering, bytes, sizeof(uint32_t));
numberWithLocalOrdering = CFSwapInt32BigToHost(numberWithNetworkOrdering);
NSLog(#"Number = %u", numberWithLocalOrdering);
bytes += sizeof(uint32_t);
length -= sizeof(uint32_t);
// Do whatever you need to with the number
}
}
Define your own internal structs and cast the pointer to it:
NSData* data;
struct headerType
{
uint16_t type;
uint32_t length;
};
const struct headerType* header=(const struct headerType*)[data bytes]; // get the header of the response
if (header->type==1)
{
const char* text=((const char*)header)+6; // skip the header (16bits+32bits=6 bytes offset)
}
EDIT:
If you need to read them in a loop:
NSData* data;
const uint8_t* cursor=(const uint8_t*)[data bytes];
while (true)
{
uint16_t type=*((uint16_t*)cursor);
cursor+=2;
if (cursor==1)
{
// string
uint32_t length=*((uint32_t*)cursor);
cursor+=4;
const char* str=(const char*)cursor;
cursor+=length;
}
else if (cursor==2)
{
// another type
}
else
break;
}
I created UUID (don't know which type) with the following code:
// Create universally unique identifier (object)
CFUUIDRef uuidObject = CFUUIDCreate(kCFAllocatorDefault);
// Get the string representation of CFUUID object.
NSString *uuidStr = (__bridge NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuidObject);
CFRelease(uuidObject);
But my API that is send data to says that is not type 1 that it needs http://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_.28MAC_address.29.
How to create this type1 UUID in objC (iphone)?
I have problems making this in obj C, is it an option to use C code to generate this?
I've been searching for the same thing. Here it is:
uuid_generate_time
https://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man3/uuid_generate_time.3.html
Also there's Apple source code for this function:
http://www.opensource.apple.com/source/xnu/xnu-792.13.8/libkern/uuid/uuid.c
NSString* uuidString = nil;
// Get UUID type 1
uuid_t dateUUID;
uuid_generate_time(dateUUID);
// Convert it to string
uuid_string_t unparsedUUID;
uuid_unparse_lower(dateUUID, unparsedUUID);
uuidString = [[NSString alloc] initWithUTF8String:unparsedUUID];
Get the MAC address first: (from developertips)
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
...
- (NSString *)getMacAddress
{
int mgmtInfoBase[6];
char *msgBuffer = NULL;
size_t length;
unsigned char macAddress[6];
struct if_msghdr *interfaceMsgStruct;
struct sockaddr_dl *socketStruct;
NSString *errorFlag = NULL;
// Setup the management Information Base (mib)
mgmtInfoBase[0] = CTL_NET; // Request network subsystem
mgmtInfoBase[1] = AF_ROUTE; // Routing table info
mgmtInfoBase[2] = 0;
mgmtInfoBase[3] = AF_LINK; // Request link layer information
mgmtInfoBase[4] = NET_RT_IFLIST; // Request all configured interfaces
// With all configured interfaces requested, get handle index
if ((mgmtInfoBase[5] = if_nametoindex("en0")) == 0)
errorFlag = #"if_nametoindex failure";
else
{
// Get the size of the data available (store in len)
if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0)
errorFlag = #"sysctl mgmtInfoBase failure";
else
{
// Alloc memory based on above call
if ((msgBuffer = malloc(length)) == NULL)
errorFlag = #"buffer allocation failure";
else
{
// Get system information, store in buffer
if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0)
errorFlag = #"sysctl msgBuffer failure";
}
}
}
// Befor going any further...
if (errorFlag != NULL)
{
NSLog(#"Error: %#", errorFlag);
return errorFlag;
}
// Map msgbuffer to interface message structure
interfaceMsgStruct = (struct if_msghdr *) msgBuffer;
// Map to link-level socket structure
socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1);
// Copy link layer address data in socket structure to an array
memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6);
// Read from char array into a string object, into traditional Mac address format
NSString *macAddressString = [NSString stringWithFormat:#"%02X:%02X:%02X:%02X:%02X:%02X",
macAddress[0], macAddress[1], macAddress[2],
macAddress[3], macAddress[4], macAddress[5]];
NSLog(#"Mac Address: %#", macAddressString);
// Release the buffer memory
free(msgBuffer);
return macAddressString;
}
Then generate the UUIDv1 with the rfc4122 spec, if the spec is too long to read, you may port the code from other language, here's one that I found: https://github.com/fredriklindberg/class.uuid.php/blob/master/class.uuid.php
Using following function you can create dynamic UUID.
-(NSString*)getDynamicUUID
{
CFUUIDRef uuidObj = CFUUIDCreate(nil);//create a new UUID
NSString *uuidString = (NSString*)CFUUIDCreateString(nil, uuidObj);
CFRelease(uuidObj);
return uuidString;
}
Hope this helps..
This is the code I am using for the encryption but it generate an error
"CCKeyDerivationPBKDF is unavailable" in AESKeyForPassword method though it is declare before implementation. How to Resolve it.
#ifndef _CC_PBKDF_H_
#define _CC_PBKDF_H_
#include <sys/types.h>
#include <sys/param.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include <Availability.h>
#include <CommonCrypto/CommonDigest.h>
#include <CommonCrypto/CommonHMAC.h>
#ifdef __cplusplus
extern "C" {
#endif
enum {
kCCPBKDF2 = 2,
};
typedef uint32_t CCPBKDFAlgorithm;
enum {
kCCPRFHmacAlgSHA1 = 1,
kCCPRFHmacAlgSHA224 = 2,
kCCPRFHmacAlgSHA256 = 3,
kCCPRFHmacAlgSHA384 = 4,
kCCPRFHmacAlgSHA512 = 5,
};
typedef uint32_t CCPseudoRandomAlgorithm;
/*
#function CCKeyDerivationPBKDF
#abstract Derive a key from a text password/passphrase
#param algorithm Currently only PBKDF2 is available via kCCPBKDF2
#param password The text password used as input to the derivation
function. The actual octets present in this string
will be used with no additional processing. It's
extremely important that the same encoding and
normalization be used each time this routine is
called if the same key is expected to be derived.
#param passwordLen The length of the text password in bytes.
#param salt The salt byte values used as input to the derivation
function.
#param saltLen The length of the salt in bytes.
#param prf The Pseudo Random Algorithm to use for the derivation
iterations.
#param rounds The number of rounds of the Pseudo Random Algorithm
to use.
#param derivedKey The resulting derived key produced by the function.
The space for this must be provided by the caller.
#param derivedKeyLen The expected length of the derived key in bytes.
#discussion The following values are used to designate the PRF:
* kCCPRFHmacAlgSHA1
* kCCPRFHmacAlgSHA224
* kCCPRFHmacAlgSHA256
* kCCPRFHmacAlgSHA384
* kCCPRFHmacAlgSHA512
#result kCCParamError can result from bad values for the password, salt,
and unwrapped key pointers as well as a bad value for the prf function.
*/
int CCKeyDerivationPBKDF( CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen,
const uint8_t *salt, size_t saltLen,
CCPseudoRandomAlgorithm prf, uint rounds,
uint8_t *derivedKey, size_t derivedKeyLen)
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
/*
* All lengths are in bytes - not bits.
*/
/*
#function CCCalibratePBKDF
#abstract Determine the number of PRF rounds to use for a specific delay on
the current platform.
#param algorithm Currently only PBKDF2 is available via kCCPBKDF2
#param passwordLen The length of the text password in bytes.
#param saltLen The length of the salt in bytes.
#param prf The Pseudo Random Algorithm to use for the derivation
iterations.
#param derivedKeyLen The expected length of the derived key in bytes.
#param msec The targetted duration we want to achieve for a key
derivation with these parameters.
#result the number of iterations to use for the desired processing time.
*/
uint CCCalibratePBKDF(CCPBKDFAlgorithm algorithm, size_t passwordLen, size_t saltLen,
CCPseudoRandomAlgorithm prf, size_t derivedKeyLen, uint32_t msec)
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
#ifdef __cplusplus
}
#endif
#endif /* _CC_PBKDF_H_ */
#import "AESEncryption.h"
#import <CommonCrypto/CommonCryptor.h>
//#import <CommonCrypto/CommonKeyDerivation.h>
//#import <CommonKeyDerivation.h>
#implementation AESEncryption
NSString * const
kRNCryptManagerErrorDomain = #"net.robnapier.RNCryptManager";
const CCAlgorithm kAlgorithm = kCCAlgorithmAES128;
const NSUInteger kAlgorithmKeySize = kCCKeySizeAES128;
const NSUInteger kAlgorithmBlockSize = kCCBlockSizeAES128;
const NSUInteger kAlgorithmIVSize = kCCBlockSizeAES128;
const NSUInteger kPBKDFSaltSize = 8;
const NSUInteger kPBKDFRounds = 1000;//0; // ~80ms on an iPhone 4
// ===================
+ (NSData *)encryptedDataForData:(NSData *)data
password:(NSString *)password
iv:(NSData **)iv
salt:(NSData **)salt
error:(NSError **)error {
NSAssert(iv, #"IV must not be NULL");
NSAssert(salt, #"salt must not be NULL");
*iv = [self randomDataOfLength:kAlgorithmIVSize];
*salt = [self randomDataOfLength:kPBKDFSaltSize];
NSData *key = [self AESKeyForPassword:password salt:*salt];
size_t outLength;
NSMutableData *
cipherData = [NSMutableData dataWithLength:data.length +
kAlgorithmBlockSize];
CCCryptorStatus
result = CCCrypt(kCCEncrypt, // operation
kAlgorithm, // Algorithm
kCCOptionPKCS7Padding, // options
key.bytes, // key
key.length, // keylength
(*iv).bytes,// iv
data.bytes, // dataIn
data.length, // dataInLength,
cipherData.mutableBytes, // dataOut
cipherData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result == kCCSuccess) {
cipherData.length = outLength;
}
else {
if (error) {
*error = [NSError errorWithDomain:kRNCryptManagerErrorDomain
code:result
userInfo:nil];
}
return nil;
}
return cipherData;
}
// ===================
+ (NSData *)randomDataOfLength:(size_t)length {
NSMutableData *data = [NSMutableData dataWithLength:length];
int result = SecRandomCopyBytes(kSecRandomDefault, length,data.mutableBytes);
NSLog(#"%d",result);
NSAssert1(result == 0, #"Unable to generate random bytes: %d", errno);
//NSAssert( #"Unable to generate random bytes: %d", errno);
return data;
}
// ===================
// Replace this with a 10,000 hash calls if you don't have CCKeyDerivationPBKDF
+ (NSData *)AESKeyForPassword:(NSString *)password
salt:(NSData *)salt {
NSMutableData *
derivedKey = [NSMutableData dataWithLength:kAlgorithmKeySize];
int result = CCKeyDerivationPBKDF(kCCPBKDF2, // algorithm
password.UTF8String, // password
password.length, // passwordLength
salt.bytes, // salt
salt.length, // saltLen
kCCPRFHmacAlgSHA1, // PRF
kPBKDFRounds, // rounds
derivedKey.mutableBytes, // derivedKey
derivedKey.length); // derivedKeyLen
NSLog(#"%d",result);
// Do not log password here
NSAssert1(result == kCCSuccess,#"Unable to create AES key for password: %d", result);
//NSAssert(#"Unable to create AES key for password: %d", result);
return derivedKey;
}
#end
The code placed above implementation is of CommonCrypto/CommonKeyDerivation.h which was not found be me xcode and hence I put code directly at the top.
Try to comment out this lines:
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
I think they limit the method to a particular Operating System and this is exactly what you don't need.
But I cannot guarantee if further issues may appear. I'm trying to achieve the same.
You have merely declared 2 prototypes for CCKeyDerivationPBKDF and CCCalibratePBKDF. Either put the full code for the functions at this place or declare them as extern and have them in a seperate module or library.