iOS/Objective C: SHA-1 and Base64 - iphone

I have to convert the phrase '1234' into the Base64-encoding of its SHA-1 hash.
I want to have: '1234' = cRDtpNCeBiql5KOQsKVyrA0sAiA=
(This example work in connection with the server communication)...
But when I checked it manualley on these sites or use my Methods in my XCode Project the result is always different:
1234
After SHA-1 (http://www.sha1.cz/)
7110eda4d09e062aa5e4a390b0a572ac0d2c0220
After Base64 (http://base64-encoder-online.waraxe.us/)
NzExMGVkYTRkMDllMDYyYWE1ZTRhMzkwYjBhNTcyYWMwZDJjMDIyMA==
This is my SHA-1 function:
- (NSString *)sha1:(NSString *)str {
const char *cStr = [str UTF8String];
unsigned char result[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(cStr, strlen(cStr), result);
NSString *s = [NSString stringWithFormat:
#"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1], result[2], result[3], result[4],
result[5], result[6], result[7],
result[8], result[9], result[10], result[11], result[12],
result[13], result[14], result[15],
result[16], result[17], result[18], result[19]
];
return [s lowercaseString];
}
For Base64 I use a this class: http://cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html
This is the call of SHA-1 and Base64:
NSString *pwHash =[self sha1:self._txtFieldPW.text]; //In my case '1234'
NSLog(#"Hash: %#",pwHash); //7110eda4d09e062aa5e4a390b0a572ac0d2c0220
//7110eda4d09e062aa5e4a390b0a572ac0d2c0220
NSData *pwHashData = [[NSData alloc]initWithData:[pwHash dataUsingEncoding:1]];
NSString *base64 = [pwHashData base64Encoding];
NSLog(#"Base64: %#",base64);
//NzExMGVkYTRkMDllMDYyYWE1ZTRhMzkwYjBhNTcyYWMwZDJjMDIyMA==
What is going wrong?

Hash is a binary value. The "cRDtpNCeBiql5KOQsKVyrA0sAiA=" string is a result of the binary value of the hash, encoded. Meanwhile, the "NzExMGVkYTRkMDllMDYyYWE1ZTRhMzkwYjBhNTcyYWMwZDJjMDIyMA==" string is the result of the Base64 transform on the hexadecimal presentation of the hash.
Did that make sense? So you have a SHA1 hash, an array of 20 bytes: {0x71, 0x10, ...}. You can Base64-encode that chunk of memory as it is. Or you can convert each byte into two lowercase hex digits, then you'll get the ASCII string "7110eda4d09e062aa5e4a390b0a572ac0d2c0220". If you apply Base64 encoding to that string, as opposed to the original hash bytes, you'll get the Base64 value "NzExMGV...".
EDIT, with extra binary goodness: reformulate the second snippet thus:
unsigned char result[CC_SHA1_DIGEST_LENGTH];
const char *cStr = [self._txtFieldPW.text UTF8String];
CC_SHA1(cStr, strlen(cStr), result); //Now result contains the hash
//Wrap the result in a NSData object
NSData *pwHashData = [[NSData alloc] initWithBytes:result length: sizeof result];
//And take Base64 of that
NSString *base64 = [pwHashData base64Encoding];
NSLog(#"Base64: %#",base64);
And get rid of the sha1 method. Once you remove the monstrous stringWithFormat call, it's a two-liner. If you really want the hex hash in the log, be my guest; but don't treat the hex string as the true value of the hash, 'cause it's not.
Unless you're using ARC, don't forget to free the NSData object afterwards.

Related

Swift SHA256 encryption returns different encrypted string compare to Objective C

I am migrating some codes from objective c to swift. I want to encrypt a string with a key using SHA 256 algorithm in swift. But comparing to Objective C implementation swift code returns different encrypted string. Both codes looks same only the syntax is different. Can someone help me get the same result in swift as I used to get in Objective C? Below are the code samples from both languages.
Objective C:
NSString* key = #"1234567890123456789012345678901234567890123456789012345678901234";
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [#"message" cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *hash = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
NSString* encryptedString = hash.base64Encoding;
Swift:
let key = "1234567890123456789012345678901234567890123456789012345678901234"
let cKey = key.cString(using: .ascii)!
let cData = "message".cString(using: .ascii)!
var digest = [CUnsignedChar](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), cKey, cKey.count, cData, cData.count, &digest)
let hash = Data(digest)
let encryptedString = hash.base64EncodedString()
The problem is that cKey and cData include the terminating null character of the strings, and in the Swift version that is counted in cKey.count and cData.count, whereas in the Objective-C version strlen(cKey) and strlen(cData) do not count the terminating null character of the strings.
Doing
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), cKey, strlen(key), cData, strlen("message", &digest)
instead would fix the issue in your example, but is not safe for non-ASCII characters.
What I actually would do is to convert the strings to Data values (which do not include a terminating null byte) with the UTF-8 representation. Then pass the underlying byte buffers to the encryption method:
let key = "1234567890123456789012345678901234567890123456789012345678901234"
let cKey = Data(key.utf8)
let cData = Data("message".utf8)
var digest = [CUnsignedChar](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
cKey.withUnsafeBytes { keyPtr in
cData.withUnsafeBytes { dataPtr in
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), keyPtr.baseAddress, cKey.count, dataPtr.baseAddress, cData.count, &digest)
}
}
let hash = Data(digest)
let encryptedString = hash.base64EncodedString()
This produces the same result ZNjnsz2Uv5L0PvWIJjSh0BrOovuRXOSFWQ0s1Rd8VSM= as your Objective-C code.

how to convert NSData to char array containing hexa values

i am receiving NSData by following method
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
server send data in follwing format
04 01 00
as hexa values. so now need to convert this data into char array so that i can access every pair separately
please help
You can go like this if you'd like to compare byte by byte:
//NSData *test; // assume this is your NSData containing 0x04 0x01 0x00
char *ptr = (void *)[test bytes]; // set a pointer to the beginning of your data bytes
if(*ptr == 0x04) {
NSLog(#"okay,.. got a 0x04");
}
ptr++; // go to the next byte
if(*ptr == 0x01) {
NSLog(#"okay,.. got a 0x01");
}
hope that does work for you.

How to convert ISO-8859-1encoded string into UTF-8 in Objective C

Does anyone know How to convert ISO-8859-1 encoded string into UTF-8 string or into NSString in Objective C ?
thanks.
Say you have your ISO-8859-1 encoded string in a varaible isoString of type const char*, then you can create an NSString instance like this:
NSString* str = [[NSString alloc]
initWithCString: isoString encoding: NSISOLatin1StringEncoding];
Note: Latin-1 and ISO-8859-1 encoding are the same.
With the following code, you can convert it to a UTF-8 encoded C string if needed:
const char* utf8String = [str UTF8String];
Or in one line:
NSString yourFinalString = [NSString stringWithCString:[yourOriginalString cStringUsingEncoding:NSISOLatin1StringEncoding] encoding:NSUTF8StringEncoding];

encrypted data return nil string

I am using Rijndael Encryption Algorithm when I am going to encrypt it, it encrypted in NSData. I want that encrypted NSdata into NSString. I tried to convert it into string but it return nil. Have anyone any solutions to get into string.
I am doing like this
NSString *passphrase = #"super-secret";
NSStringEncoding myEncoding = NSUTF8StringEncoding;
NSString *alphaPlain = #"This is a encryption test.";
NSData *alphaDataPlain = [alphaPlain dataUsingEncoding:myEncoding];
NSLog(#" SimpleText value : %#",alphaPlain);
NSData *alphaDataCypher = [alphaDataPlain AESEncryptWithPassphrase:passphrase];
NSString *alphaStringCypher = [[NSString alloc] initWithData:alphaDataCypher encoding:myEncoding];
NSLog(#" Encrypted value : %#",alphaStringCypher);
It returns nil value.
Thanks
The encrypted data is no longer a UTF8 string, it's just some sequence of bytes, so decoding it as UTF8 fails.
What do you want to do with the string? If it's just for logging/debugging purposes, you could use [myData description] to get a hex string (with some extra whitespace for better readability). If you need this to transfer the data in a context where you need a textual representation, converting it to Base64 would be a good idea, see this answer for an easy way to do that.

iOS Development: How can I encapsulate a string in an NSData object?

I'm building a multiplayer game on the iPhone and I need to send string data to the other players in the game. To do that, I need to encapsulate my NSString* string data in an NSData object somehow. Here's an example of how my code is structured...
typedef struct
{
PACKETTYPE packetType;
??? stringToSend; //<---not sure how to store this
} StringPacket;
StringPacket msg;
msg.packetType = STRING_PACKET;
msg.stringToSend = ... // <---not sure what to do here
NSData *packet = [NSData dataWithBytes:&msg length:sizeof(StringPacket)];
So my question is, if StringPacket is a struct defined in my header, what type should the stringToSend property be so that I can easily call the dataWithBytes method of NSData to encapsulate the packet data in an NSData object?
Thanks for your wisdom!
At first, you should convert your NSString to UTF8 representation via [NSString UTF8String].
After that, i'd recommend to store in packet string length, and after that - the string characters themself. All that can be done via appending NSData, created from char* via [NSData dataWithBytes:]
NSMutableData packet = [[NSMutableData alloc] init];
[packet appendBytes:&msg.packetType, sizeof(msg.packetType)];
char *str = [yourString UTF8String];
int len = strlen(str);
[packet appendBytes:(void*)&len, sizeof(len)];
[packet appendBytes:(void*)str, len];
To parse packet back, you should do:
NSData packet; // your packet
[packet getBytes:(void*)&packet.msg range:NSMakeRange(0, sizeof(packet.msg))];
int len;
[packet getBytes:(void*)&len range:NSMakeRange(sizeof(packet.msg), sizeof(len)];
NSData *strData = [packet subdataWithRange:NSMakeRange(sizeof(packet.msg) + sizeof(len)), packet.length];
NSString *str = [[NSString alloc] initWithData:strData encoding:UTF8Encoding];
There can be some mistakes since i'm writing from memory, but I think you'll get the idea.
If your strings have a maximum length, it's rather easy and can be done efficiently. So, assuming your strings max length for these packets is 255 and you've decided to use UTF-8 to encode your strings (both sides need to agree which encoding they're using), you could do it like this:
typedef struct
{
PACKETTYPE packetType;
uint8_t stringToSend[256]; // UTF8 string with max encoded length of 255 bytes
} StringPacket;
StringPacket msg;
msg.packetType = STRING_PACKET;
[theString getCString:msg.stringToSend maxLength:256 encoding:NSUTF8StringEncoding];
NSData *packet = [NSData dataWithBytes:&msg length:sizeof(StringPacket)];
Now you will have a proper C string in your packet that is at most 255 bytes of string data and the null terminator. Note, if your string can't be encoded to UTF8 in the size you gave it, the method will return NO, so your real code should actually check for that and handle it.
If you can't have a size limit, you can basically do the same thing, but you have to deal with dynamically allocating the memory, copying the bytes, creating the data and properly freeing the memory at the right time, so it becomes much more involved but it's the same basic idea. See also the method -getBytes:maxLength:usedLength:encoding:options:range:remainingRange: on NSString, it can be very useful in generating these messages where the string size is dynamic and totally unknown.
For the most simple case, however, the code above should get the job done.