I am trying to make an app for my school that interacts with PowerSchool, a software that allows user's to view their grades, teachers, schedules, and much more. I found a library for the basics of interacting with PowerSchool written in PHP and have been trying to write it in objective c for the past week. It seems the issue is how I create an HMAC (MD5) with the user's password. Either I am using a hex digest rather than a digest, not sure. The error I get back from the server is an odd number of characters. Here is the link to the PHP library class I am trying to re-create: https://github.com/horvste/powerapi-php/blob/master/src/PowerAPI/Core.php Here is my code in my test project, Command line main class: https://gist.github.com/anonymous/c40cdd99a826c06073aa NSString Category Implementation file:
#import "NSString+MyAdditions.h"
@implementation NSString (MyAdditions)
- (NSString *) hmacMD5WithData: (NSString *) data
{
const char *cKey = [self cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
const unsigned int blockSize = 64;
char ipad[blockSize], opad[blockSize], keypad[blockSize];
unsigned int keyLen = strlen(cKey);
CC_MD5_CTX ctxt;
if(keyLen > blockSize)
{
//CC_MD5(cKey, keyLen, keypad);
CC_MD5_Init(&ctxt);
CC_MD5_Update(&ctxt, cKey, keyLen);
CC_MD5_Final((unsigned char *)keypad, &ctxt);
keyLen = CC_MD5_DIGEST_LENGTH;
}
else
{
memcpy(keypad, cKey, keyLen);
}
memset(ipad, 0x36, blockSize);
memset(opad, 0x5c, blockSize);
int i;
for(i = 0; i < keyLen; i++)
{
ipad[i] ^= keypad[i];
opad[i] ^= keypad[i];
}
CC_MD5_Init(&ctxt);
CC_MD5_Update(&ctxt, ipad, blockSize);
CC_MD5_Update(&ctxt, cData, strlen(cData));
unsigned char md5[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(md5, &ctxt);
CC_MD5_Init(&ctxt);
CC_MD5_Update(&ctxt, opad, blockSize);
CC_MD5_Update(&ctxt, md5, CC_MD5_DIGEST_LENGTH);
CC_MD5_Final(md5, &ctxt);
const unsigned int hex_len = CC_MD5_DIGEST_LENGTH*2+2;
char hex[hex_len];
for(i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
{
snprintf(&hex[i*2], hex_len-i*2, "%02x", md5[i]);
}
NSData *HMAC = [[NSData alloc] initWithBytes:hex length:strlen(hex)];
NSString *hash = [HMAC base64EncodedStringWithOptions:0];
return hash;
}
@end
Thank you for taking the time to look at this issue!
First, don't build your own HMAC routine here. Use CCHmac. It's built-in and handles HMAC+MD5 correctly.
If at all possible, I recommend going to the API documentation rather than trying to reverse engineer another code base. There are lots of little things going on in the PHP that you may be overlooking; an API doc should explain all of those.
If the PHP code is the only reference you have, then you should break down each piece and see where it's going wrong. For instance, verify that you are getting the auth data in the same form. Then confirm that each program, given the same auth data generates the same HMAC. Then confirm that given the same HMAC, each program generates the same response. Etc. Somewhere you are doing something differently. Make sure that you're using Base64 vs raw data in the same places (PHP devs tend to treat Base64 strings as though they were actually raw data, which causes confusion when coming over to ObjC).
And of course you should examine the server logs to validate that your final request matches the PHP requests.