I'm developing an app that uses a barcode to pull data from an API.
For each call I need to generate a hash value as a signature. Which is a combination of my API ID and the barcode.
I've got an issue where my hashed value is the same each time, therefore my calls are failing.
The functions to create the hash are in objective-C and I have a bridge so I can call it in SwiftUI.
NSString+SHA1.m
#import "NSString+SHA1.h"
#import <CommonCrypto/CommonHMAC.h>
#implementation NSString (SHA1)
- (NSString *)hashedValue:(NSString *)key
{
const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
const char *cData = [self cStringUsingEncoding:NSUTF8StringEncoding];
unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
NSString *hash = [HMAC base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
//Used to be [HMAC base64Encoding], but is now depreciated
return hash;
}
#end
As base64Encoding is depreciated, I tried to use base64EncodedStringWithOptions instead. This may be done incorrectly and could be the cause of why my hash value is the same each time.
This is how I call it in SwiftUI:
let hashedValue = scannedCode.barcode.hashedValue("(API ID)")
scannedCode is an observable object that stores the scanned barcode under "barcode" as a String.
In the bridging header:
#import "NSString+SHA1.h"
#import "NSString+SHA1.m"
NSString+SHA1.h
#import <Foundation/Foundation.h>
#interface NSString (SHA1)
- (NSString *)hashedValue:(NSString *)key;
#end
EDIT:
I fixed the problem of the hash value being the same, but the API still isn't accepting my signature. So it's to do with the calculation being wrong.
Related
I want to generate SHA512 with salt in iOS. I found following snippet to achieve this but I found that CCHmac() function is for mac.
-(NSString *)hashString:(NSString *)data withSalt:(NSString *)salt
{
const char *cKey = [salt cStringUsingEncoding:NSUTF8StringEncoding];
const char *cData = [data cStringUsingEncoding:NSUTF8StringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSString *hash;
NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
[output appendFormat:#"%02x", cHMAC[i]];
}
hash = output;
return hash;
}
If I use CC_SHA512() function, then how will I use the salt string?
I was missing following line:
#import <CommonCrypto/CommonHMAC.h>
Actually, < CommonCrypto / CommonCryptor.h > was already added in my code. So, at first look, I thought that there is no worry about importing particular header file. But, suddenly I realize that I will have to import another header file.
Example of SHA256 HMAC:
+ (NSData *)doHmac:(NSData *)dataIn key:(NSData *)salt
{
NSMutableData *macOut = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
CCHmac( kCCHmacAlgSHA256,
salt.bytes, salt.length,
dataIn.bytes, dataIn.length,
macOut.mutableBytes);
return macOut;
}
I am trying to implement password hashing in my iPad application.I found secure salted password hashing link which is having sample codes of java, .net ,etc but not ios. Can anybody help me to found a solution in the same way how they are doing...
Use common crypto library for making md5 of your password.
#import <CommonCrypto/CommonDigest.h>
and then use.
- (NSString *) md5:(NSString *) input
{
const char *cStr = [input UTF8String];
unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5( cStr, strlen(cStr), digest ); // This is the md5 call
NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
[output appendFormat:#"%02x", digest[i]];
return output;
}
Note that MD5 is insecure and shouldn't be used for hashing sensitive information such as passwords. You should instead use SHA1 or SHA256 like this:
+ (NSData *)sha256:(NSData *)data {
unsigned char hash[CC_SHA256_DIGEST_LENGTH];
if(CC_SHA256([data bytes], [data length], hash) ) {
NSData *sha256 = [NSData dataWithBytes:hash length: CC_SHA256_DIGEST_LENGTH];
return sha256;
}
return nil;
}
I am trying to encrypt a string with HMAC-SHA1 using CCHmac(). I created an NSString category
for this:
NSString+HMAC.h
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonHMAC.h>
#interface NSString (HMAC)
- (NSString *)HMACSHA1WithKey:(NSString *)key;
#end
NSString+HMAC.m
#import "NSString+HMAC.h"
#implementation NSString (HMAC)
- (NSString *)HMACSHA1WithKey:(NSString *)key
{
const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
const char *cData = [self cStringUsingEncoding:NSUTF8StringEncoding];
unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
return [[NSString alloc] initWithData:HMAC encoding:NSUTF8StringEncoding];
}
#end
I am using this category from RubyMotion like so:
key = "ZjiUOHkl5tllz2PwaoZYrDRMkg9b43k5CcIOUjSE&"
string = "POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_consumer_key=XXX&oauth_nonce=OWhJeFpZbzRoVU4xck1RTENyN0w4T1J0czNIa01rSVA&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1389974660&oauth_version=1.0"
string.HMACSHA1WithKey(key) # => nil
However, the HMACSHA1WithKey: method returns nil all the time...
What am I doing wrong please?
The result of the SHA-1 algorithm (which is stored in HMAC) is a sequence of
bytes, but not a valid UTF-8 sequence. Therefore
[[NSString alloc] initWithData:HMAC encoding:NSUTF8StringEncoding]
fails and returns nil.
What you probably want is to convert the NSData *HMAC to a NSString containing the hexadecimal representation of the data.
There are many solutions available for that, for example How to convert an NSData into an NSString Hex string?.
Can anybody point me in the right direction to be able to encrypt a string, returning another string with the encrypted data? (I've been trying with AES256 encryption.) I want to write a method which takes two NSString instances, one being the message to encrypt and the other being a 'passcode' to encrypt it with - I suspect I'd have to generate the encryption key with the passcode, in a way that can be reversed if the passcode is supplied with the encrypted data. The method should then return an NSString created from the encrypted data.
I've tried the technique detailed in the first comment on this post, but I've had no luck so far. Apple's CryptoExercise certainly has something, but I can't make sense of it... I've seen lots of references to CCCrypt, but it's failed in every case I've used it.
I would also have to be able to decrypt an encrypted string, but I hope that's as simple as kCCEncrypt/kCCDecrypt.
Since you haven't posted any code, it's difficult to know exactly which problems you're encountering. However, the blog post you link to does seem to work pretty decently... aside from the extra comma in each call to CCCrypt() which caused compile errors.
A later comment on that post includes this adapted code, which works for me, and seems a bit more straightforward. If you include their code for the NSData category, you can write something like this: (Note: The printf() calls are only for demonstrating the state of the data at various points — in a real application, it wouldn't make sense to print such values.)
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *key = #"my password";
NSString *secret = #"text to encrypt";
NSData *plain = [secret dataUsingEncoding:NSUTF8StringEncoding];
NSData *cipher = [plain AES256EncryptWithKey:key];
printf("%s\n", [[cipher description] UTF8String]);
plain = [cipher AES256DecryptWithKey:key];
printf("%s\n", [[plain description] UTF8String]);
printf("%s\n", [[[NSString alloc] initWithData:plain encoding:NSUTF8StringEncoding] UTF8String]);
[pool drain];
return 0;
}
Given this code, and the fact that encrypted data will not always translate nicely into an NSString, it may be more convenient to write two methods that wrap the functionality you need, in forward and reverse...
- (NSData*) encryptString:(NSString*)plaintext withKey:(NSString*)key {
return [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
}
- (NSString*) decryptData:(NSData*)ciphertext withKey:(NSString*)key {
return [[[NSString alloc] initWithData:[ciphertext AES256DecryptWithKey:key]
encoding:NSUTF8StringEncoding] autorelease];
}
This definitely works on Snow Leopard, and #Boz reports that CommonCrypto is part of the Core OS on the iPhone. Both 10.4 and 10.5 have /usr/include/CommonCrypto, although 10.5 has a man page for CCCryptor.3cc and 10.4 doesn't, so YMMV.
EDIT: See this follow-up question on using Base64 encoding for representing encrypted data bytes as a string (if desired) using safe, lossless conversions.
I have put together a collection of categories for NSData and NSString which uses solutions found on Jeff LaMarche's blog and some hints by Quinn Taylor here on Stack Overflow.
It uses categories to extend NSData to provide AES256 encryption and also offers an extension of NSString to BASE64-encode encrypted data safely to strings.
Here's an example to show the usage for encrypting strings:
NSString *plainString = #"This string will be encrypted";
NSString *key = #"YourEncryptionKey"; // should be provided by a user
NSLog( #"Original String: %#", plainString );
NSString *encryptedString = [plainString AES256EncryptWithKey:key];
NSLog( #"Encrypted String: %#", encryptedString );
NSLog( #"Decrypted String: %#", [encryptedString AES256DecryptWithKey:key] );
Get the full source code here:
https://gist.github.com/838614
Thanks for all the helpful hints!
-- Michael
#owlstead, regarding your request for "a cryptographically secure variant of one of the given answers," please see RNCryptor. It was designed to do exactly what you're requesting (and was built in response to the problems with the code listed here).
RNCryptor uses PBKDF2 with salt, provides a random IV, and attaches HMAC (also generated from PBKDF2 with its own salt. It support synchronous and asynchronous operation.
I waited a bit on #QuinnTaylor to update his answer, but since he didn't, here's the answer a bit more clearly and in a way that it will load on XCode7 (and perhaps greater). I used this in a Cocoa application, but it likely will work okay with an iOS application as well. Has no ARC errors.
Paste before any #implementation section in your AppDelegate.m or AppDelegate.mm file.
#import <CommonCrypto/CommonCryptor.h>
#implementation NSData (AES256)
- (NSData *)AES256EncryptWithKey:(NSString *)key {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
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 numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer); //free the buffer;
return nil;
}
- (NSData *)AES256DecryptWithKey:(NSString *)key {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
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 cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer); //free the buffer;
return nil;
}
#end
Paste these two functions in the #implementation class you desire. In my case, I chose #implementation AppDelegate in my AppDelegate.mm or AppDelegate.m file.
- (NSString *) encryptString:(NSString*)plaintext withKey:(NSString*)key {
NSData *data = [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
return [data base64EncodedStringWithOptions:kNilOptions];
}
- (NSString *) decryptString:(NSString *)ciphertext withKey:(NSString*)key {
NSData *data = [[NSData alloc] initWithBase64EncodedString:ciphertext options:kNilOptions];
return [[NSString alloc] initWithData:[data AES256DecryptWithKey:key] encoding:NSUTF8StringEncoding];
}
Please use the below mentioned URL to encrypt string using AES excryption with
key and IV values.
https://github.com/muneebahmad/AESiOSObjC
So I'm trying to figure out how to do a hmacshad256 hash on ios as that's the hash I did for the wcf service api I made. I've been trying to look for some info about it but would usually just end up getting a SHA-256 hash.
This is the only reference I have:
Need to generate HMAC SHA256 hash in Objective C as in Java
And I'm not sure if that's the only way to do it (importing a java hmac class)
Any help is appreciated.
Thanks!
NSString * parameters = #"string to hash"
NSString *salt = #"saltStringHere";
NSData *saltData = [salt dataUsingEncoding:NSUTF8StringEncoding];
NSData *paramData = [parameters dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData* hash = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH ];
CCHmac(kCCHmacAlgSHA256, saltData.bytes, saltData.length, paramData.bytes, paramData.length, hash.mutableBytes);
NSString *base64Hash = [hash base64Encoding];
and also
#import <CommonCrypto/CommonHMAC.h>
Since base64Encoding is deprecated from iOS 7.0, the last line should be:
NSString *base64Hash = [hash base64EncodedStringWithOptions:0];
Here is the solution I'm submitting that I put together from other answers on the matter:
This is easily adapted to other hash types by changing CC_SHA256_DIGEST_LENGTH and kCCHmacAlgSHA256.
If you're interested in doing that, check out the CommonDigest.h file within the CommonCrypto library.
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCrypto.h>
+ (NSString *)hmac:(NSString *)plaintext withKey:(NSString *)key
{
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [plaintext cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];
const unsigned char *buffer = (const unsigned char *)[HMACData bytes];
NSMutableString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2];
for (int i = 0; i < HMACData.length; ++i){
[HMAC appendFormat:#"%02x", buffer[i]];
}
return HMAC;
}
This has been tested on iOS 8.x and iOS 7.x
+ (NSString *)hmacSHA256EncryptString{
NSString * parameterSecret = #"input secret key";
NSString *plainString = #"input encrypt content string";
const char *secretKey = [parameterSecret cStringUsingEncoding:NSUTF8StringEncoding];
const char *plainData = [plainString cStringUsingEncoding:NSUTF8StringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, secretKey, strlen(secretKey), plainData, strlen(plainData), cHMAC);
NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];
const unsigned char *bufferChar = (const unsigned char *)[HMACData bytes];
NSMutableString *hmacString = [NSMutableString stringWithCapacity:HMACData.length * 2];
for (int i = 0; i < HMACData.length; ++i){
[hmacString appendFormat:#"%02x", bufferChar[i]];
}
return hmacString;
}