I'm trying to use CommonCrypto to generate keys using PBKDF2 but I can't seem to import CommonCrypto/CommonKeyDerivation.h, I just errors that it is not found.
Any ideas?
edit: I should probably mention I have already added the security framework and I can import all of the other CommonCrypto headers.
Here's how i generate AES256 keys. The only interesting this is that i get CommonCrypto to estimate for me how many rounds to use. It seems pretty straightforwards.
#import <CommonCrypto/CommonKeyDerivation.h>
...
// Makes a random 256-bit salt
- (NSData*)generateSalt256 {
unsigned char salt[32];
for (int i=0; i<32; i++) {
salt[i] = (unsigned char)arc4random();
}
return [NSData dataWithBytes:salt length:32];
}
...
// Make keys!
NSString* myPass = #"MyPassword1234";
NSData* myPassData = [myPass dataUsingEncoding:NSUTF8StringEncoding];
NSData* salt = [self generateSalt256];
// How many rounds to use so that it takes 0.1s ?
int rounds = CCCalibratePBKDF(kCCPBKDF2, myPassData.length, salt.length, kCCPRFHmacAlgSHA256, 32, 100);
// Open CommonKeyDerivation.h for help
unsigned char key[32];
CCKeyDerivationPBKDF(kCCPBKDF2, myPassData.bytes, myPassData.length, salt.bytes, salt.length, kCCPRFHmacAlgSHA256, rounds, key, 32);
Add this library to your project libcommonCrypto.dylib
#import into hash key generation class.
use following code to generate hash key.
This is the code what i have used:
// Salt data getting from salt string.
NSData *saltData = [#"Salt String" dataUsingEncoding:NSUTF8StringEncoding];
// Data of String to generate Hash key(hexa decimal string).
NSData *passwordData = [#"Hash key generated string" dataUsingEncoding:NSUTF8StringEncoding];
// Hash key (hexa decimal) string data length.
NSMutableData *hashKeyData = [NSMutableData dataWithLength:CC_SHA1_DIGEST_LENGTH];
// Key Derivation using PBKDF2 algorithm.
int result = CCKeyDerivationPBKDF(kCCPBKDF2, passwordData.bytes, passwordData.length, saltData.bytes, saltData.length, kCCPRFHmacAlgSHA1, 1000, hashKeyData.mutableBytes, hashKeyData.length);
// Hexa decimal or hash key string from hash key data.
NSString *hexDecimalString = hashKeyData.description;
NSLog(#"Hexa decimal string:%#", hexDecimalString);
Are you building for iOS5 ? or earlier versions ?
Both API, CCKeyDerivationPBKDF and CCCalibratePBKDF, defined in the header file are only available on IOS5 (or OSX 10.7) and later.
You can make sure the file exists by executing this inside a terminal window:
$ find /Developer/ -name CommonKeyDerivation.h
/Developer//Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/usr/include/CommonCrypto/CommonKeyDerivation.h
/Developer//Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/usr/include/CommonCrypto/CommonKeyDerivation.h
/Developer//SDKs/MacOSX10.7.sdk/usr/include/CommonCrypto/CommonKeyDerivation.h
Related
I have been working on this for a while, but can not find a way to tackle the problem. Hopefully one of you can tell me what I am missing.
I am using NSURLConnection to download base64 encoded data containing AES128 encrypted data. What I have is the key, see code, and the knowledge that the first 16 characters of the encrypted data is the IV. What I want is to decode the data and then decrypt it using the key and iv extracted. This is what I have so far:
- (void) connectionDidFinishLoading:(NSURLConnection *) connection {
NSLog(#"Succeeded! Downloaded %d bytes of data", downloadData.length);
NSData *decoded_EncryptedData = [downloadData base64EncodedDataWithOptions:0];
NSString *decoded_EncryptedString = [[NSString alloc] initWithData: decoded_EncryptedData encoding:NSUTF8StringEncoding];
const void *key = #"0000000000000000000000000000000"; // key of length 32 char -> i know standard format for AES128 encryption is 16, maybe this requires 256 AES decryption
const void *iv = (__bridge const void *)([decoded_EncryptedString substringWithRange:NSMakeRange(0,16)]);
NSString *encryptedString = [decoded_EncryptedString substringWithRange:NSMakeRange(16, decoded_EncryptedString.length-16)];
// Now I have no idea what needs to happen, but from online research I found it should be something like this:
NSData encryptedData = [encryptedString dataUsingEncoding:NSUTF8StringEncoding]; // Writing it back into a data file
// Find size of returned data
size_t Size = encryptedData.length + kCCBlockSizeAES128;
// Initialise returned data
NSMutableData *decryptedData = [NSMutableData dataWithLength:Size];
// allocate variable to numBytesDecrypted
size_t numBytesDecrypted;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0, KCCKeySizeAES128, iv,
[encryptedData bytes], [encryptedData length], [decryptedData bytes], [decryptedData length],
&numBytesDecrypted);
// Now I test whether the decryption process was successful:
if (cryptStatus == kCCSuccess) {
NSLog(#"Successfully decrypted);
NSString *decryptedString = [[NSString alloc] initWithData:decryptedData encoding: NSUTF8StringEncoding];
}
}
The above code does display Successfully decrypted, however the string return null and size 0. Could someone please help me solve this? I would be so grateful.
Kind regards,
Lennaert
You have many problems.
You really need to know if the encryption is AES128 or AES256.
Encryption is data based, not string based. The conversion to a string decoded_EncryptedString is incorrect not should not be done.
The key is an issue, using a string is generally a bad idea, it is expected to be data bytes. Possibly the key is specified in hex so 32 hex characters would be 128 bits. If so conversion to data will be required.
'iv' and encryptedString are strings but they should be data, this a result of 2 above.
The key is not passed to CCCrypt.
Padding is generally used since the data is rarely exactly a block size in length, you probably need to specify PKCS7 padding to CCCrypt. You need to know if padding was used and if so was it PKCS7, php for example uses non-standard padding.
If PKCS7 padding is used the result must be trimmed to the length based on the variable numBytesDecrypted. If some other padding is used that must be trimmed.
If you want more help please supply test data and the result.
Finally, try and check back more frequently.
In My App, i'm getting data from xml, where it is encrypted, and i need to decrypt the received nsstring,
UserName = #"QEjbHvzPjk+YuLDVPUJuEA==";
I Need to decrypt this nsstring into regular format, i searched and find aes , but it doesn't make any changes,
NSString* msg = [FBEncryptorAES decryptBase64String:UserName
keyString:#"01234567890abcdefghijklmnopqrstuvwxyz"];
if (msg)
{
UserName = msg;
NSLog(#"decrypted: %#", msg);
} else
{
UserName = #"(failed to decrypt)";
}
How can i decrypt the above nsstring, Thanks in Advance.
The string is not only AES encrypted, it is Base64 encoded. The trailing "==" is typical of base64 padding. Also AES encryption produces data bytes, not ASCII characters and the output is a multiple of the block size. It is common to Base64 encode the result of encryption so it is ASCII and can be included in XML.
For iOS 7 there are several Base64 API methods for NSData. Probably what you want is:
- (id)initWithBase64EncodedString:(NSString *)base64String options:(NSDataBase64DecodingOptions)options
Example:
NSString *userName = #"QEjbHvzPjk+YuLDVPUJuEA==";
NSData *data = [[NSData alloc] initWithBase64EncodedString:userName options:0];
NSLog(#"data: %#", data);
NSLog output:
data: <4048db1e fccf8e4f 98b8b0d5 3d426e10>
The data probably is AES encrypted, it is a multiple of block length, and if so you will need the key and also information on padding, mode and possibly iv.
Note that the FBEncryptorAES class method encryptedBase64String does accept Base64 input but the decryption key string is suspect and the encryption may not match this decryption method due to method and possible iv. So the FBEncryptorAES class may not be what you need.
Due to the inadequacies of µTorrent's response system when sending through either magnet links or torrent files, that is, the complete lack of a message for duplicate torrent adding, I am attempting to get the hash from a torrent file before it's sent over and comparing that with the list of current jobs. The code I currently have is returning an incorrect hash and I haven't a clue why.
Here is the code I'm using.
I'm attempting to send through a file with a hash of "dc9202f98aea7420a2872655c8f7184401e2a9c8", this code is returning one of thirty or so hashes every time it's run.
+ (NSString *) torrentHashFromFile:(NSData *)file
{
NSString * retVal = #"";
NSData * data = [BEncoding encodedDataFromObject:
[[BEncoding objectFromEncodedData:file]
objectForKey:#"info"]];
unsigned char hashBytes[CC_SHA1_DIGEST_LENGTH];
if (CC_SHA1([data bytes], (unsigned)[data length], hashBytes))
{
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
{
[output appendFormat:#"%02x", hashBytes[i]];
}
retVal = output;
}
return retVal;
}
What makes you think a BT info hash is a SHA1 over just the piece hashes?
Quoting BEP-0003:
info_hash
The 20 byte sha1 hash of the bencoded form of the info value from the metainfo file.
Note that this is a substring of the metainfo file.
Previously I did Triple DES encryption to encrypt some data using a string key file, by defining a method
+ (NSData *)tripleDESEncryptWithKey:(NSString *)key dataToEncrypt:(NSData*)convertedData {}.
Now, similarly I am doing AES 256 encryption. But this time, I can not use a string as the key. I need to get NSData from a file in resources using
NSData *keyData = [NSData dataWithContentsOfFile:keyPath];
As I need to pass this key as parameter, I tried to convert it into string with
NSString *key = [[NSString alloc] initWithData:keyData encoding:NSUTF8StringEncoding];
but it returned NULL. So, How to use the Data key for AES 256 encryption ?
EDIT: I got that I should not use UTF8 encoding as the data file was made by Base64 encoding of a string. So Now the question is, how to get the string key using Base64 from keyData ?
If key variable returned NULL. Try to use like this.
NSString* key = [NSString stringWithUTF8String:[keyData bytes]];
Refer to KennyTM's Answer
UPDATE 1: You can also read the string directly from your file without convert in NSData
By NSFileHandle:
NSString * path = #"your key file path";
NSFileHandle * fileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
NSData * buffer = nil;
while ((buffer = [fileHandle readDataOfLength:1024])) {
//do something with buffer
}
or use NSString
NSString * key = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
Refer to Dave DeLong's Answer
Note: Ensure your keyPath variable , Is it correct in the format of full or relative path?
UPDATE 2: You can also deal with Base64 Encoding with Matt Gallagher NSData+Base64 Class&Header (See also his blog there)
For encode base64
NSString * key = [[path dataUsingEncoding:NSUTF8StringEncoding] base64EncodedString];
Hope it helps you!
Read the file:
NSData* myData = [NSData dataWithContentsOfFile:myFileWithPath];
Then use one of the implementations in this post:
Base64 encoding options on the Mac and iPhone
to do your Base64 conversion.
Note: simply sticking your decryption key into a file is a bad idea. Optimally, the key would be stored securely by being encrypted by the user's own key.
I am attempting to convert an HMAC (hashed data) to a string safe for urls for authentication purposes.
Im having problems converting data generated from sha256 hashing (using apples crypto library) to Unicode in both little and big Endian, one hashed string will work in big and not in little, and visa versa for a different hashed string. For some hashed
strings it works perfectly. I think it may have something to do with an out of range character or something. When I say it doesn't work, I mean it returns nil.
The code looks like this:
NSString *mystring = [[NSString alloc] initWithData:myHash encoding:NSUnicodeEncoding
Is Unicode the best to use? I tried encoding to UTF8, it returns nil and ascii doesn't have all the characters, I get a few "?" where data is missing.
Really, my question is, how do I make A string from NSData from a sha256 hash?
Solution:
https://github.com/eczarny/xmlrpc
NSData+Base64.h and NSData+Base64.m
You first need to make a hex string out of your HMAC bytes.
You can make it like this:
void bytes_to_hexstring(void *uuid, char *hex_string, size_t osize) {
static const char hexdigits[] = "0123456789ABCDEF";
const unsigned char* bytes = (unsigned char *)uuid;
int i = 0;
for (i = 0; i<osize; ++i) {
const unsigned char c = *bytes++;
*hex_string++ = hexdigits[(c >> 4) & 0xF];
*hex_string++ = hexdigits[(c ) & 0xF];
}
*hex_string = 0;
}
char *mystring = malloc(41);
bytes_to_hexstring(myHash, mystring, 20);
something like this.