How does AES-128 CBC encryption with IV work in objective-C? - objective-c

I am trying to encrypt a string with 'AES-128 CBC with IV'. Here is the input parameter and expected output:
Key:
000102030405060708090A0B0C0D0E0F
IV:
00102030405060708090A0B0C0D0E0F0
Input data:
EA010B23CDA9B16F0001020304050607
Output:
B773C36749E87D3F8FED98FE52026A15
I have verified the output on this web site:
http://extranet.cryptomathic.com/aescalc/index?key=000102030405060708090A0B0C0D0E0F&iv=00102030405060708090A0B0C0D0E0F0&input=EA010B23CDA9B16F0001020304050607&mode=cbc&action=Encrypt&output=B773C36749E87D3F8FED98FE52026A15
How to encrypt a string with AES-128 CBC with IV in objective C? (With same result as http://extranet.cryptomathic.com/aescalc) I am trying to get the encrypted string - B773C36749E87D3F8FED98FE52026A15 , but no luck.
I have tried to use this library for the encryption: https://github.com/Pakhee/Cross-platform-AES-encryption/tree/master/iOS
Here is my objective c code:
NSString* data = #"EA010B23CDA9B16F0001020304050607";
NSString* key = #"000102030405060708090A0B0C0D0E0F";
NSString* iv = #"00102030405060708090A0B0C0D0E0F0";
NSData *encryptedData = [[StringEncryption alloc] encrypt:[#"EA010B23CDA9B16F0001020304050607" dataUsingEncoding:NSUTF8StringEncoding] key:key iv:iv];
NSLog(#"encryptedData %#", encryptedData);
The output of encryptedData is:
<68f8ed75 e79f2ba2 c80e67a2 f0c84b7a c4b07fd1 59e937e5 14644cba c0ddb60c 40502375 7798e7a1 58bd05a5 b3d9e7bd>
I expect the value of *encryptedData should be <42373733 43333637 34394538 37443346 38464544 39384645 35323032 36413135>, which is hex of B773C36749E87D3F8FED98FE52026A15
I have tried another library - https://github.com/dev5tec/FBEncryptor
NSData* _data = [data dataUsingEncoding:NSUTF8StringEncoding];
NSData* _key = [key dataUsingEncoding:NSUTF8StringEncoding];
NSData* _iv = [iv dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedData2 = [FBEncryptorAES encryptData:_data key:_key iv:_iv];
NSLog(#"encryptedData2 = %#", encryptedData2);
Output is <2beea977 aef69eb1 ed9f6dd0 7bf5f1ce d1e5df46 2cbf8465 773f122d 03267abb 2e113d9b 07189268 4fd6babe 7b1c0056>
It seems that I am using wrong library or I have wrong input to the encryption function. Any recommendation of AES library for objective c?

Common Crypto is the correct thing to use for encryption for iOS and OSX. The issue it to provide the correct input.
The input key, iv and data appear to be in hexadecimal. Cryptomathic expects it inputs to be in hexadecimal and it's output is in hexadecimal so it works correctly.
But the ObjC code uses:
NSString* data = #"EA010B23CDA9B16F0001020304050607";
NSData* _data = [data dataUsingEncoding:NSUTF8StringEncoding];
which uses the hexadecimal as a character string.
Instead use a hex to data conversion such as #Larme linked to, see the first comment.
From the sizes of the input and output it appears you are using PKCS#7 padding which adds a full block of padding if the input is an exact multiple of the block size, Cryptomathic does not add PKCS#7 padding.
Update
#interface Crypt : NSObject
+ (NSData *)aes128Data:(NSData *)dataIn;
+ (NSData *)dataFromHexString:(NSString *)hexString;
#end
#implementation Crypt
+ (NSData *)aes128Data:(NSData *)dataIn
operation:(CCOperation)operation // kCC Encrypt, Decrypt
key:(NSData *)key
options:(CCOptions)options // kCCOption PKCS7Padding, ECBMode,
iv:(NSData *)iv
error:(NSError **)error
{
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0;
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
ccStatus = CCCrypt( operation,
kCCAlgorithmAES,
options,
key.bytes, key.length,
iv.bytes,
dataIn.bytes, dataIn.length,
dataOut.mutableBytes, dataOut.length,
&cryptBytes);
if (ccStatus == kCCSuccess) {
dataOut.length = cryptBytes;
}
else {
if (error) {
*error = [NSError errorWithDomain:#"kEncryptionError"
code:ccStatus
userInfo:nil];
}
dataOut = nil;
}
return dataOut;
}
+ (NSData *)dataFromHexString:(NSString *)hexString {
char buf[3];
buf[2] = '\0';
unsigned char *bytes = malloc([hexString length]/2);
unsigned char *bp = bytes;
for (CFIndex i = 0; i < [hexString length]; i += 2) {
buf[0] = [hexString characterAtIndex:i];
buf[1] = [hexString characterAtIndex:i+1];
char *b2 = NULL;
*bp++ = strtol(buf, &b2, 16);
}
return [NSData dataWithBytesNoCopy:bytes length:[hexString length]/2 freeWhenDone:YES];
}
#end
NSString *dataHexString = #"EA010B23CDA9B16F0001020304050607";
NSString *keyHexString = #"000102030405060708090A0B0C0D0E0F";
NSString *ivHexString = #"00102030405060708090A0B0C0D0E0F0";
NSLog(#"dataHexString: %#", dataHexString);
NSLog(#"keyHexString: %#", keyHexString);
NSLog(#"ivHexString: %#", ivHexString);
NSData *data = [Crypt dataFromHexString:dataHexString];
NSData *key = [Crypt dataFromHexString:keyHexString];
NSData *iv = [Crypt dataFromHexString:ivHexString];
NSLog(#"data: %#", data);
NSLog(#"key: %#", key);
NSLog(#"iv: %#", iv);
NSError *error;
NSData *encryptedData = [Crypt
aes128Data:data
operation:kCCEncrypt
key:key
options:0
iv:iv
error:&error];
NSLog(#"encryptedData %#", encryptedData);
Output:
dataHexString: EA010B23CDA9B16F0001020304050607
keyHexString: 000102030405060708090A0B0C0D0E0F
ivHexString: 00102030405060708090A0B0C0D0E0F0
data: <ea010b23 cda9b16f 00010203 04050607>
key: <00010203 04050607 08090a0b 0c0d0e0f>
iv: <00102030 40506070 8090a0b0 c0d0e0f0>
encryptedData: <b773c367 49e87d3f 8fed98fe 52026a15>
Note encryptedData matches the Cryptomathic result.

Related

How to encrypt with AES 256 CBC in Objective C

I am building an iPhone app which gets a encrypt string and sent it to backend.
In PHP I am encrypting the string like this:
$encrypt_method = "AES-256-CBC";
$secret_key = 'This is my secret key';
$secret_iv = 'This is my secret iv';
// hash
$key = hash('sha256', $secret_key);
// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);
if( $action == 'encrypt' ) {
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
}
How I do the same like that but in Objective C
#import <CommonCrypto/CommonCryptor.h>
#define key #"YOUR_KEY"
#define iv #"YOUR_IV"
- (NSData *) cryptOperation:(CCOperation)operation
{
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keys[kCCKeySizeAES256 + 1];
[key getCString:keys maxLength:sizeof(keys) encoding:NSUTF8StringEncoding];
// Perform PKCS7Padding on the key.
unsigned long bytes_to_pad = sizeof(keys) - [key length];
if (bytes_to_pad > 0)
{
char byte = bytes_to_pad;
for (unsigned long i = sizeof(keys) - bytes_to_pad; i < sizeof(keys); i++)
keys[i] = byte;
}
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus status = CCCrypt(operation, kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
keys, kCCKeySizeAES256,
[iv UTF8String],
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (status == kCCSuccess)
{
//the returned NSData takes ownership of buffer and will free it on dealloc
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer); //free the buffer;
return nil;
}
- (NSData *)AES256Encrypt
{
return [self cryptOperation:kCCEncrypt];
}
- (NSData *)AES256Decrypt
{
return [self cryptOperation:kCCDecrypt];
}
you can use this method by following way..
NSString *receivedDataDecryptString = [self decrypt:#"YOUR_STRING"];
NSString *receivedDataEncryptString = [self encrypt:#"YOUR_STRING"];
-(NSString *)encrypt:(NSString *)string
{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
NSData *dataEncrypted = [data AES256Encrypt];
NSString *strRecordEncrypted = [dataEncrypted base64EncodedStringWithOptions:0];
return strRecordEncrypted;
}
-(NSString *)decrypt:(NSString *)string
{
if([string containsString:#"\n"] || [string containsString:#"\t"])
{
string = [[string componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] componentsJoinedByString:#""];
string = [string stringByReplacingOccurrencesOfString:#"\t" withString:#""];
}
NSData *keyData = [[NSData alloc] initWithBase64EncodedString:string options:0];
NSData *dataDecrypted = [keyData AES256Decrypt];
NSString *receivedDataDecryptString = [[NSString alloc]initWithData:dataDecrypted encoding:NSUTF8StringEncoding];
return receivedDataDecryptString;
}
Thanks Nirav Kotecha for your answer.
I ended up using CrytoSwift and Add Extension class NSString and String to call it.

Different HMac Digest are being generated every time for the same input in objective c

Trying to get the digest using HMac SHA256 with below code but every time it is giving different output.
Here key parameter is in Base64string format while plaintext parameter is without any encoding.
+(NSString *)hmacWithIndicies:(NSString *)plaintext withKey:(NSString *)key {
NSLog(#"Input text::%#",plaintext);
NSLog(#"Input Key::%#",key);
NSData *keyData = [[NSData alloc] initWithBase64EncodedString:key options:0];
NSLog(#"Key Data is::%#",keyData);
const char *cKey = (char *)[keyData bytes];
NSLog(#"Key Length is::%lu",strlen(cKey));
NSData *keyInData = [NSData dataWithBytes:cKey length:sizeof(cKey)];
NSLog(#"Key data = %#", keyInData);
//Data here
const char *cData = [plaintext cStringUsingEncoding:NSUTF8StringEncoding];
NSLog(#"Input Length is::%lu",strlen(cData));
NSData *dataData = [NSData dataWithBytes:cData length:sizeof(cData)];
NSLog(#"Input data = %#", dataData);
uint8_t cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *hMacInData =[[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
NSLog(#"Hash Mac data generated is %#", hMacInData);
NSString *b64EncStrHmac = [hMacInData base64EncodedStringWithOptions:0];
NSLog(#"Hash Mac generated is %#", b64EncStrHmac);
return b64EncStrHmac;
}
Calling the above method as below:-
NSString * hMacOutput= [KeyGeneration hmacWithIndicies:#"2SagarPra2983688" withKey:#"qDwki5t1SSuKER4mzSMBHXhtt+PRMCv0B2LgXaBZmgE="];
NSLog(#"Output of HMac digest::%#",hMacOutput);
hMacOutput digest is resulting in different output every time it is being called.
You can not use strlen() on non "C" strings, "C" strings are null terminated strings that do not contain any 0x00 bytes. strlen() counts until it finds the first 0x00 byte, on data bytes that could be early or past the end of the data, possible causing a crash.
You are trying to hard, there is no reason for "C" style arrays, just use the bytes member of NSData and NSMutableData along with the length method.
[NSMutableData dataWithLength: ] allocates memory.
Example:
+(NSString *)hmacWithIndicies:(NSString *)plaintext withKey:(NSString *)key {
NSLog(#"Input text: %#", plaintext);
NSLog(#"Input Key: %#", key);
NSData *keyData = [[NSData alloc] initWithBase64EncodedString:key options:0];
NSLog(#"keyData Length: %lu, Data: %#", keyData.length, keyData);
NSData *inData = [plaintext dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"inData Length: %lu, Data: %#", inData.length, inData);
NSMutableData *HMACdata = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, keyData.bytes, keyData.length, inData.bytes, inData.length, (void *)HMACdata.bytes);
NSLog(#"Hash Mac data generated: %#", HMACdata);
NSString *b64EncStrHmac = [HMACdata base64EncodedStringWithOptions:0];
NSLog(#"Hash Mac generated: %#", b64EncStrHmac);
return b64EncStrHmac;
}
Output:
Input text: 2SagarPra2983688
Input Key: qDwki5t1SSuKER4mzSMBHXhtt+PRMCv0B2LgXaBZmgE=
keyData Length: 32, Data: a83c248b 9b75492b 8a111e26 cd23011d 786db7e3 d1302bf4 0762e05d a0599a01
inData Length: 16, Data: 32536167 61725072 61323938 33363838
Hash Mac data generated: b681d2b1 251f1953 3716258c 8eeb9101 db3ecad2 c4a5077e 0cf76617 e45e5459
Hash Mac generated: toHSsSUfGVM3FiWMjuuRAds+ytLEpQd+DPdmF+ReVFk=
Output of HMac digest::toHSsSUfGVM3FiWMjuuRAds+ytLEpQd+DPdmF+ReVFk=
It is not possible to use strlen for binary data. As the key of HMAC can be of any size you may be using more bytes than the key actually contains. If the key changes each time, you will get different output. You need to retrieve the size of the key from keyData, not from a cKey.

Getting Different Result for AES256Encryption in objective c?

For Encryption using following function:
https://gist.github.com/Veelian/7541502
Whenever I read file in binary and apply encryption on it,
I get some encrypted text of that file but whenever I execute
same above operation again then i will get different encrypted text
File is same contents of file also same, still getting different encrypted text
if execute same operation again.
Please find the below code
NSString *filePath = #"/Users/xyx/Desktop/NOTICE.txt";
const char *cfilePath = [filePath cStringUsingEncoding:NSASCIIStringEncoding];
FILE *fileStream= fopen (cfilePath,"rb");
NSDictionary *properties = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
NSNumber *fileSize = [properties objectForKey: NSFileSize];
long l_fileSize = [fileSize longValue];
temp = (char*) malloc (sizeof(char)*l_fileSize);
fgetpos(fileStream,&pos);
int bytesToRead = (int)l_fileSize;
size_t byt=fread(temp,1,bytesToRead,fileStream);
buffer = [NSData dataWithBytes:(const void *)temp length:sizeof(char)*byt];
NSLog(#"Buffer : %#",buffer);
BytesRead = buffer.length;
NSData *encryptedBytes=[buffer AES256EncryptWithKey:[Security key]]; //taking key from other class
size_t length = [encryptedBytes length] + 1;
unsigned char aBuffer[length];
[encryptedBytes getBytes:aBuffer length:length];
NSString *encBytes = [NSString stringWithFormat:#"%s", aBuffer];
NSLog(#"ENcrypted Bytes : %#",encBytes);

encrypt nsstring with 3des ios7

I am new with iOS7 development and objective c, and i need to develop an application which will send encrypted data with 3DES to a server,I have searched in stack overflow and Net but still unable to get it work, finally i tried this code but i got null as result,
+ (NSString*)encrypt:(NSString*)plainText withKey:(NSString*)key{
uint8_t keyByte[kSecrectKeyLength];
NSMutableData *keyData = [[NSMutableData alloc] init];
int i;
for (i=0; i < [key length] / 2; i++) {
NSString *tempNumber = [key substringWithRange: NSMakeRange(i * 2, 2)];
NSScanner *scanner=[NSScanner scannerWithString:tempNumber];
unsigned int temp;
[scanner scanHexInt:&temp];
Byte B = (Byte)(0xFF & temp);
keyByte[i] = B;
}
NSData* data = [plainText dataUsingEncoding:NSUTF8StringEncoding];
size_t plainTextBufferSize = [data length];
const void *vplainText = (const void *)[data bytes];
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x0, bufferPtrSize);
const void *vkey = (const void *) keyByte;
const void *vinitVec = (const void *) [gIv UTF8String];
ccStatus = CCCrypt(kCCEncrypt,
kCCAlgorithm3DES,
kCCOptionPKCS7Padding,
vkey,
kCCKeySize3DES,
vinitVec,
vplainText,
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
&movedBytes);
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
//NSString *result = [GTMBase64 stringByEncodingData:myData];
NSString *result = [[NSString alloc] initWithData:myData encoding:NSUTF8StringEncoding];
NSLog(#"result=%#",result);
return result;
}
Please have u any idea about the solution???
lol i just struggled with this myself the other day, i have a working solution now using this code
+ (NSData *)tripleDesEncryptString:(NSString *)input
key:(NSString *)key
error:(NSError **)error
{
NSParameterAssert(input);
NSParameterAssert(key);
NSData *inputData = [input dataUsingEncoding:NSUTF8StringEncoding];
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
size_t outLength;
NSAssert(keyData.length == kCCKeySize3DES, #"the keyData is an invalid size");
NSMutableData *outputData = [NSMutableData dataWithLength:(inputData.length + kCCBlockSize3DES)];
CCCryptorStatus
result = CCCrypt(kCCEncrypt, // operation
kCCAlgorithm3DES, // Algorithm
kCCOptionPKCS7Padding | kCCOptionECBMode, // options
keyData.bytes, // key
keyData.length, // keylength
nil,// iv
inputData.bytes, // dataIn
inputData.length, // dataInLength,
outputData.mutableBytes, // dataOut
outputData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result != kCCSuccess) {
if (error != NULL) {
*error = [NSError errorWithDomain:#"com.your_domain.your_project_name.your_class_name."
code:result
userInfo:nil];
}
return nil;
}
[outputData setLength:outLength];
return outputData;
}
+ (NSString *)tripleDesDecryptData:(NSData *)input
key:(NSString *)key
error:(NSError **)error
{
NSParameterAssert(input);
NSParameterAssert(key);
NSData *inputData = input;
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
size_t outLength;
NSAssert(keyData.length == kCCKeySize3DES, #"the keyData is an invalid size");
NSMutableData *outputData = [NSMutableData dataWithLength:(inputData.length + kCCBlockSize3DES)];
CCCryptorStatus
result = CCCrypt(kCCDecrypt, // operation
kCCAlgorithm3DES, // Algorithm
kCCOptionPKCS7Padding | kCCOptionECBMode, // options
keyData.bytes, // key
keyData.length, // keylength
nil,// iv
inputData.bytes, // dataIn
inputData.length, // dataInLength,
outputData.mutableBytes, // dataOut
outputData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result != kCCSuccess) {
if (error != NULL) {
*error = [NSError errorWithDomain:#"com.your_domain.your_project_name.your_class_name."
code:result
userInfo:nil];
}
return nil;
}
[outputData setLength:outLength];
return [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding];
}
you probably want to base64 encode the data the comes out of the encryption method, and then un-base64 anything that you want to decrypt as well, there are built in methods for NSData to do this now, eg:
[data base64EncodedDataWithOptions:(NSDataBase64EncodingOptions)];
to test if the functions work, i used this test function
+ (void) testEncryptionAndDecryption {
NSData *encrypted = [self tripleDesEncryptString:#"test" key:#"123456789123456789123456" error:nil];
NSLog(#"encrypted data length: %lu", (unsigned long)encrypted.length);
NSString *decrypted = [self tripleDesDecryptData:encrypted key:#"123456789123456789123456" error:nil];
NSLog(#"decrypted text: %#", decrypted);
}
this gave me the correct output that you would expect

NSString from NSData always null

I would like to sign a request with HMAC SHA512, but I seem to mess up encoding and decoding from and to NSData and NSString. I desperately tried to figure out what is wrong, but I just don't seem to get it right.
PSEUDOCODE:
function hmac_512(msg, sec) {
sec = Base64Decode(sec);
result = hmac(msg, sec, sha512);
return Base64Encode(result);
}
secret = "7pgj8Dm6";
message = "Test\0Message";
result = hmac_512(message, secret);
if (result == "69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO3mQxlsWNPrw==")
print("Success!");
else
printf("Error: %s", result);
My implementation:
+(void)doSomeMagic{
NSString *message = #"Test\0Message";
NSString *signedRequest = [self signRequestForParameterString:message];
//checking against CORRECT (from JAVA equivalent) signed request
if ([signedRequest isEqualToString:#"69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO3mQxlsWNPrw==" ])
NSLog(#"Success!");
else
NSLog(#"Error!");
}
Here is the signing method:
+(NSString *)signRequestForParameterString:(NSString*)paramStr{
NSString *secret = #"7pgj8Dm6";
// secret is base64 encoded, so I decode it
NSData *decodedSecret = [secret base64DecodedData];
NSString *decodedSecretString = [NSString stringWithUTF8String:[decodedSecret bytes]];
NSData *data = [paramStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *dataString = [NSString stringWithUTF8String:[data bytes]];
return [self generateHMACSHA512Hash:decodedSecretString data:dataString];
}
Here is the hashing function:
+(NSString *)generateHMACSHA512Hash:(NSString *)key data:(NSString *)data{
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA512, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC
length:sizeof(cHMAC)];
NSString *hash = [HMAC base64EncodedString];
return hash;
}
I am pretty sure it is due to the encoding of the strings (decodedSecretString and dataString). decodedSecretString (decoded base64) after decoding is encoded in ASCII. However, when I call the hashing method, I encode it in ascii again, which will result in a null error. Everything is confusing me right now.
Your secret doesn't decode to a valid UTF-8 string, and Java allows NUL bytes in strings, but when you're converting "Test\0Message" to a C string and using strlen, its length is 4.
Something like this should work:
+(NSString *)signRequestForParameterString:(NSString*)paramStr{
NSString *secret = #"7pgj8Dm6";
NSData *data = [paramStr dataUsingEncoding:NSUTF8StringEncoding];
return [self generateHMACSHA512Hash:[secret base64DecodedData] data:data];
}
+(NSString *)generateHMACSHA512Hash:(NSData *)key data:(NSData *)data{
unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA512, key.bytes, key.length, data.bytes, data.length, cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
return [HMAC base64EncodedString];
}
When doing HMAC or other cryptographic functions, you should build up some fundamental methods/functions that don't deal with strings first. Then you can create wrapper methods that decode/encode string data or digests in a convenient way.
+ (NSData *)dataBySigningData:(NSData *)data withKey:(NSData *)key
{
unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA512, [key bytes], [key length], [data bytes], [data lenght], cHMAC);
return [[NSData alloc] initWithBytes:cHMAC length:CC_SHA512_DIGEST_LENGTH];
}
+ (NSData *)dataBySigningMessage:(NSString *)message withKey:(NSData *)key
{
return [self dataBySigningData:[message dataUsingEncoding:NSUTF8StringEncoding]
withKey:[key dataUsingEncoding:NSUTF8StringEncoding]];
}
(Note: this code is not tested, just hacked together in a text editor)
Don't worry about the string representation of your key or data. Then you can go from there, e.g. getting the base64 encoding of the digest.
Cryptographic functions DO NOT CARE about strings or text encodings. They care about bytes. Strings (in C, since they are null-terminated) are a mere subset of what can be represented in data. So it would be severely limiting to deal with strings.