Has any one implemented CBC Mac (DESede) in Objective c? Could you show sample code or explain how to correct my code?
Here is my effort so far....
-(void)tryMac
{
unsigned char blockCount;
unsigned char key[16] = "\x1\x2\x3\x4\x5\x6\x7\x8\x9\x0\x1\x2\x3\x4\x5\x6";
unsigned char data[16] = "\x54\x68\x69\x73\x69\x73\x6d\x79\x73\x74\x72\x69\x6e\x67\x0\x0";
DES_cblock *desKey1 = (DES_cblock* ) key;
DES_cblock *desKey2 = (DES_cblock* ) key;
unsigned char *iv = (unsigned char *) malloc(8);
memset(iv, 0x0, 8);
DES_set_odd_parity(desKey1);
DES_set_odd_parity(desKey2);
DES_key_schedule schedule1;
DES_key_schedule schedule2;
DES_set_key_checked(desKey1, &schedule1);
DES_set_key_checked(desKey2, &schedule2);
int len = sizeof(data);
blockCount = len / 4;
int lastBlock = 0;
for(unsigned char i = 0; i < blockCount; i++)
{
int bufferLen = sizeof(data)/blockCount;
unsigned char buffer[bufferLen];
memccpy(buffer, data, lastBlock, bufferLen);
lastBlock = (i + 1) * bufferLen;
unsigned char *result = (unsigned char *) malloc(4);
if (lastBlock == len)
{
DES_ede2_cbc_encrypt(buffer, result, bufferLen, &schedule1, &schedule2, (DES_cblock *) iv, DES_ENCRYPT);
NSData *encryptedData = [NSData dataWithBytes:(const void *)result length:4];
NSString *encryptedString = [self stringWithHexFromData:encryptedData];
NSLog(#"Encrypted Block %#",encryptedString);
}
}
Related
I am trying to divide an unsigned char array and place it in 3 variables.
The original variable: 0000000300000008544368616d696568
The output should be :
tag= **00000003**
length = **00000005**
value = **544368616d696568**
To get the tag & length:
- (BOOL)decodeTag:(unsigned char*) data{
unsigned char *byteTag;
byteTag = [self CopyArray:byteTag :0 :data :0 :4*2];
NSString *s=[NSString stringWithUTF8String:(char *)byteTag];
NSString *dataAsString = [s substringWithRange:NSMakeRange(0, [s length])];
unsigned intData = 0;
NSScanner *scanner = [NSScanner scannerWithString:dataAsString];
[scanner scanHexInt:&intData];
int tag = intData;
self.tag = tag;
NSLog(#"decode tag %i", tag);
return true;
}
To get the value:
- (BOOL)decodeValue:(unsigned char*) data{
unsigned char* value=(unsigned char *)calloc(self.length*2, sizeof(unsigned char));
value= [self CopyArrays:value :0 :data :8*2 : self.length *2];
self.value = value;
NSLog(#"data %s",data);
NSLog(#"value %s",value);
return true;
}
To copy a part of the unsigned char array:
- (unsigned char*)CopyArrays:(unsigned char *) destination :(int) destIndex :(unsigned char *) source :(int) sourceIndexStart :(int) length{
for ( int i=0; i<length; i++){
destination[i+destIndex] = source[i+sourceIndexStart];
}
return destination;
}
But as a result for the value variable, i get the following:
544368616d696568\255\276\232zY\300ݺ
I have NSMutableData "30352514 38001300 00000001"
i need convert byte to bit
00110000001101
and that to NSString
Thx
Use this for bytes:
const char *byte = [data bytes];
NSLog(#"%s",byte);
This is for bits:
const char *byte = [data bytes];
unsigned int length = [data length];
for (int i=0; i<length; i++) {
char n = byte[i];
char buffer[9];
buffer[8] = 0; //for null
int j = 8;
while(j > 0)
{
if(n & 0x01)
{
buffer[--j] = '1';
} else
{
buffer[--j] = '0';
}
n >>= 1;
}
printf("%s ",buffer);
My server devs ask me to send them some data encoded with base64 with this rules:
big-endian byte order
no extra zero bytes
base64 string
for example:
10005000 → «mKol»
1234567890 → «SZYC0g»
I did some spaghetti code, and it's work. But maybe somebody have more elegant solution?
+ (NSString*)encodeBigEndianBase64:(uint32_t)value {
char *bytes = (char*) &value;
int len = sizeof(uint32_t);
char *reverseBytes = malloc(sizeof(char) * len);
unsigned long index = len - 1;
for (int i = 0; i < len; i++)
reverseBytes[index--] = bytes[i];
int offset = 0;
while (reverseBytes[offset] == 0) {
offset++;
}
NSData *resultData;
if (offset > 0) {
int truncatedLen = (len - offset);
char *truncateBytes = malloc(sizeof(char) * truncatedLen);
for (int i = 0; i < truncatedLen ; i++)
truncateBytes[i] = reverseBytes[i + offset];
resultData = [NSData dataWithBytes:truncateBytes length:truncatedLen];
free(truncateBytes);
} else {
resultData = [NSData dataWithBytes:reverseBytes length:len];
}
free(reverseBytes);
return [[resultData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength] stringByReplacingOccurrencesOfString:#"=" withString:#""];
}
Little bit improved solution (thanks to zaph):
+ (NSString*)encodeBigEndianBase64:(uint32_t)value {
uint32_t swappedValue = CFSwapInt32HostToBig(value);
char *swappedBytes = (char*) &swappedValue;
int len = sizeof(uint32_t);
int offset = 0;
while (swappedBytes[offset] == 0) {
offset++;
}
NSData *resultData;
if (offset > 0) {
int truncatedLen = (len - offset);
char *truncateBytes = malloc(sizeof(char) * truncatedLen);
for (int i = 0; i < truncatedLen ; i++)
truncateBytes[i] = swappedBytes[i + offset];
resultData = [NSData dataWithBytes:truncateBytes length:truncatedLen];
free(truncateBytes);
} else {
resultData = [NSData dataWithBytes:swappedBytes length:len];
}
return [[resultData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength] stringByReplacingOccurrencesOfString:#"=" withString:#""];
}
For endian conversions use htons(), htonl(), ntohs(), ntohl()
network byte order is bigendian
`htons()` // host to network short
`htonl()` // host to network ling
`ntohs()` // network to host long
`ntohl()` // network to host long
These are defined in endan.h
Also see Byte-Order Utilities Reference
I'm working with a partner and we're not able to get C# and Objective-C to produce the same hashes using what we think are the same tools in the respective languages. In C#, I'm doing this:
byte[] noncebytes=new byte[32];
//We seed the hash generator with a new 32 position array. Each position is 0.
//In prod code this would be random, but for now it's all 0s.
HMACSHA256 hmac256 = new HMACSHA256(noncebytes);
string plaintext = "hello";
string UTFString = Convert.ToBase64String(
System.Text.Encoding.UTF8.GetBytes(plaintext));
string HashString = Convert.ToBase64String(
hmac256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(plaintext))); //Convert that hash to a string.
This produces the following base64string hash:
Q1KybjP+DXaaiSKmuikAQQnwFojiasyebLNH5aWvxNo=
What is the equivalent Objective-C code to do this? We need the client and the server to be able to generate matching hashes for matching data.
Here is the Objective-C code we are currently using:
...
NSData *zeroNumber = [self zeroDataWithBytes:32]; //empty byte array
NSString *nonceTest = [zeroNumber base64String]; // using MF_Base64Additions.h here
NSData *hashTest = [self hmacForKeyAndData:nonceTest withData:#"hello"]; //creating hash
NSString *hashTestText = [hashTest base64String];
NSLog(#"hello hash is %#", hashTestText);
...
//functions for zeroing out the byte. I'm sure there's a better way
- (NSData *)zeroDataWithBytes: (NSUInteger)length {
NSMutableData *mutableData = [NSMutableData dataWithCapacity: length];
for (unsigned int i = 0; i < length; i++) {
NSInteger bits = 0;
[mutableData appendBytes: (void *) &bits length: 1];
} return mutableData;
}
//hash function
-(NSData *) hmacForKeyAndData:(NSString *)key withData:(NSString *) data {
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
}
UPDATE:
There is a pretty good project on GitHub that seems to accomplish everything you want, plus a lot more encryption related options; includes unit tests.
NSData *hmacForKeyAndData(NSString *key, NSString *data)
{
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
}
(Source)
With the above, I think you will have import <CommonCrypto/CommonHMAC.h>. The next step for encoding to Base64:
+ (NSString *)Base64Encode:(NSData *)data
{
//Point to start of the data and set buffer sizes
int inLength = [data length];
int outLength = ((((inLength * 4)/3)/4)*4) + (((inLength * 4)/3)%4 ? 4 : 0);
const char *inputBuffer = [data bytes];
char *outputBuffer = malloc(outLength);
outputBuffer[outLength] = 0;
//64 digit code
static char Encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//start the count
int cycle = 0;
int inpos = 0;
int outpos = 0;
char temp;
//Pad the last to bytes, the outbuffer must always be a multiple of 4
outputBuffer[outLength-1] = '=';
outputBuffer[outLength-2] = '=';
/* http://en.wikipedia.org/wiki/Base64
Text content M a n
ASCII 77 97 110
8 Bit pattern 01001101 01100001 01101110
6 Bit pattern 010011 010110 000101 101110
Index 19 22 5 46
Base64-encoded T W F u
*/
while (inpos < inLength){
switch (cycle) {
case 0:
outputBuffer[outpos++] = Encode[(inputBuffer[inpos]&0xFC)>>2];
cycle = 1;
break;
case 1:
temp = (inputBuffer[inpos++]&0x03)<<4;
outputBuffer[outpos] = Encode[temp];
cycle = 2;
break;
case 2:
outputBuffer[outpos++] = Encode[temp|(inputBuffer[inpos]&0xF0)>> 4];
temp = (inputBuffer[inpos++]&0x0F)<<2;
outputBuffer[outpos] = Encode[temp];
cycle = 3;
break;
case 3:
outputBuffer[outpos++] = Encode[temp|(inputBuffer[inpos]&0xC0)>>6];
cycle = 4;
break;
case 4:
outputBuffer[outpos++] = Encode[inputBuffer[inpos++]&0x3f];
cycle = 0;
break;
default:
cycle = 0;
break;
}
}
NSString *pictemp = [NSString stringWithUTF8String:outputBuffer];
free(outputBuffer);
return pictemp;
}
Note the second line of code in the objective-c portion of the question.
NSString *nonceTest = [zeroNumber base64String];
but it should be this:
NSString *nonceTest = [[NSString alloc] initWithData:zeroNumber encoding:NSASCIIStringEncoding];
It was a case of converting the string to base64 when we didn't need to for the hmac seeeding.
We now get: Q1KybjP+DXaaiSKmuikAQQnwFojiasyebLNH5aWvxNo= as the hash on both platforms.
md5 a string multiple times in Python:
def md5(i):
return hashlib.md5(i).hexdigest().upper()
def md5x3(src):
f = hashlib.md5(src).digest()
s = hashlib.md5(f).digest()
t = md5(s)
return t
how to implement above in C with OpenSSL on MacOS/iOS or in Objective-C without OpenSSL on MacOS/iOS ?
I'm try following, but its result is different from python's.
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
static char* hextostr(const unsigned char* in , int len)
{
char* res = (char*)malloc(len * 2 + 1);
int i = 0;
memset(res , 0 , len * 2 + 1);
while(i < len)
{
sprintf(res + i * 2 , "%02x" , in[i]);
i ++;
};
// i = 0;
// int reslength;
// reslength=(int)strlen(res);
// while(i < reslength)
// {
// res[i] = toupper(res[i]);
// i ++;
// };
return res;
}
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString * foo = #"abcdefghij";
NSData * buf1 = [foo dataUsingEncoding:NSUTF8StringEncoding];
unsigned char result1[CC_MD5_DIGEST_LENGTH];
CC_MD5([buf1 bytes], (unsigned int)[buf1 length], result1);
NSData * buf2 = [[[NSString alloc] initWithFormat:#"%s", result1] dataUsingEncoding:NSUTF8StringEncoding];
unsigned char result2[CC_MD5_DIGEST_LENGTH];
CC_MD5(result1, (unsigned int)strlen(result1), result2);
NSData * buf3 = [[[NSString alloc] initWithFormat:#"%s", result2] dataUsingEncoding:NSUTF8StringEncoding];
unsigned char result3[CC_MD5_DIGEST_LENGTH];
CC_MD5(result2, (unsigned int)strlen(result2), result3);
NSString * res = [[NSString alloc] initWithFormat:
#"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
result3[0], result3[1], result3[2], result3[3], result3[4], result3[5], result3[6], result3[7],
result3[8], result3[9], result3[10], result3[11], result3[12], result3[13], result3[14], result3[15]
];
NSLog(#"%s", hextostr(result1, CC_MD5_DIGEST_LENGTH));
NSLog(#"%s", hextostr(result2, CC_MD5_DIGEST_LENGTH));
NSLog(#"%s", hextostr(result3, CC_MD5_DIGEST_LENGTH));
[pool drain];
return 0;
}
Use a digest library, such as OpenSSL, which you probably have installed already. See http://www.openssl.org/docs/crypto/md5.html. Source code for MD5 is available at http://userpages.umbc.edu/~mabzug1/cs/md5/md5.html.