I have an encryption function that gets data and key, with inner iv and returns an encrypted string. I can encrypt every string that contains just English characters but not about Arabic. This is my function. Please help me to find the problem. Thanks
-(NSString*)Encrypt:(NSString*)data second:(NSString*)key
{
size_t outLength;
NSMutableData * cipherData = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128];
Byte byte[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,}; //It`s not valid. The main iv is secret
NSData *datakey = [NSData dataWithBytes:key.UTF8String length:key.length];
NSData *datadata = [NSData dataWithBytes:data.UTF8String length:data.length];
CCCryptorStatus result = CCCrypt( kCCEncrypt
, kCCAlgorithmAES128
, kCCOptionPKCS7Padding
, datakey.bytes
, [datakey length]
, byte
, datadata.bytes
, [datadata length]
, cipherData.mutableBytes
, cipherData.length
, &outLength);
if (result == kCCSuccess) {
cipherData.length = outLength;
}
else {
}
NSData *encryptedData=cipherData;
NSString *str=[encryptedData base64EncodedStringWithOptions: NSDataBase64Encoding64CharacterLineLength];
return str;
}
The problem is that cipherData is to short. It need to be a block longer than datadata which may (such as in this case) be longer than data.length.
When creating data with utf-8 encoding from a string that contains multiple-byte data such as Arabic, emoji and etc the data will be longer than the string characters.
Incorrect code:
NSMutableData * cipherData = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128];
NSData *datadata = [NSData dataWithBytes:data.UTF8String length:data.length];
Correct code:
NSData *datadata = [data dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData * cipherData = [NSMutableData dataWithLength: datadata.length + kCCBlockSizeAES128];
Note that misnaming the input string data does not help, it is a string. renaming data -> tex and then ``datadata->data` makes the code more clear. Good naming solves many code problems.
Related
Hi need to encrypt this string
NSString *iv = #"12345678910111211";
NSString *key = #"12345678910111211";
NSString *dataString2 = #"eJDRqD_1ME0:APA91bFRfuy6Xk0GMVHtFLKjw5eZnqoGQ7wdTYjXdLGPqOVGuApv_eaZQzHQmqhqTKN70mspUt6BpZFFnCGn4j2y0Ew-eS1SnghLQZNxNAbh9LSgCjviWGe2wwCCW132jqW5E_aaxL5g";
NSData *dataIn2 = [dataString2 dataUsingEncoding:NSUTF8StringEncoding];
NSData *result2 = [BBAES encryptedDataFromData:dataIn2 IV:ivData key:symKey options:0]; // result = 16bytes
NSData *hexaData2 = result2;
NSString *DataHexadecimalString2 = [hexaData2 hexadecimalString];
NSLog(#"Encrypted hexa = %#", DataHexadecimalString2);
Output I am getting is:
6bd95973e91de1330e3195098104116b0f888533bfeb0f20edcbcdf66a9e5d79676b8b33b62c470454003dc5013d92efb191b1b07e320b1cff59874007191d72be18e8b2784dcfc8c2960b59879b9c14c42421105ac356d5bccc7ee0f70122f8c2a47743984ba453a02b82b7ddd770fd5284483d3581c818076f9c87569345ab558c2e286ceb1388d6444042ecb10d0ccb294488ed51c86de20b85b076bb2d85
Expected output is this:
6bd95973e91de1330e3195098104116b0f888533bfeb0f20edcbcdf66a9e5d79676b8b33b62c470454003dc5013d92efb191b1b07e320b1cff59874007191d72be18e8b2784dcfc8c2960b59879b9c14c42421105ac356d5bccc7ee0f70122f8c2a47743984ba453a02b82b7ddd770fd5284483d3581c818076f9c87569345ab558c2e286ceb1388d6444042ecb10d0c46530088a27a522ba365d6942a83ac41
Don't know what I am doing wrong. Can any one help me?
This is a great example of why not to use mcrypt.
The input string is 153 bytes, it will require padding to 160 bytes, either specify a padding option or there will be an error. In this case it looks like the encryption function just took whatever bytes followed the input in memory.
One solution is to specify PKCS#7 (née PKCS#5) padding.
Added information: mcrypt and null padding is being used, just add enough null bytes to the encrypted data to bring it up to an exact multiple of the block size (AES block size is 16-bytes).
You need to do two things:
1) Add trailing 0x00 bytes, in this example add 8:
NSString *dataString2 = #"eJDRqD_1ME0:APA91bFRfuy6Xk0GMVHtFLKjw5eZnqoGQ7wdTYjXdLGPqOVGuApv_eaZQzHQmqhqTKN70mspUt6BpZFFnCGn4j2y0Ew-eS1SnghLQZNxNAbh9LSgCjviWGe2wwCCW132jqW5E_aaxL5g\x00\x00\x00\x00\x00\x00\x00\x00";
2) In BBAES remove the PKCS#7 padding
CCCryptorStatus status = CCCryptorCreate(operation, kCCAlgorithmAES128, kCCOptionPKCS7Padding, [key bytes], [key length], [iv bytes], &cryptor);
to
CCCryptorStatus status = CCCryptorCreate(operation, kCCAlgorithmAES128, 0, [key bytes], [key length], [iv bytes], &cryptor);
Just using Common Crypto (warning, no error checking in example):
NSData *ivData = [#"0q1z2a3a4p5a6789" dataUsingEncoding:NSUTF8StringEncoding];
NSData *keyData = [#"9876a5p4a3a2z1q0" dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedData = [#"eJDRqD_1ME0:APA91bFRfuy6Xk0GMVHtFLKjw5eZnqoGQ7wdTYjXdLGPqOVGuApv_eaZQzHQmqhqTKN70mspUt6BpZFFnCGn4j2y0Ew-eS1SnghLQZNxNAbh9LSgCjviWGe2wwCCW132jqW5E_aaxL5g\x00\x00\x00\x00\x00\x00\x00\x00" dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *plainData = [NSMutableData dataWithLength: encryptedData.length];
size_t movedBytes = 0;
CCCryptorStatus ccStatus;
ccStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
0, // Bad idea not to use PKCS#7 padding (kCCOptionPKCS7Padding)
keyData.bytes, kCCKeySizeAES128,
ivData.bytes,
encryptedData.bytes, encryptedData.length,
plainData.mutableBytes, plainData.length,
&movedBytes);
plainData.length = movedBytes;
NSLog(#"Data: \n%#",plainData);
You can of course add the null bytes with a code loop but the best is not to use mcrypt and use PKCS#7 (née PKCS#5) padding.
I am trying to decrypt an AES encryption with the following information provided:
Encryption type: AES 128
Mode: CBC
Padding: PKCS5 (.net uses PKCS7)
Password(key): jayjay
Encryption ref: https://zenu.wordpress.com/2011/09/21/aes-128bit-cross-platform-java-and-c-encryption-compatibility/
Example provided:
Encrypted string: vsiv+Tv0H9Tz0GHtf2S4KBXVV+0L6Wr0xCWwA1QOPs8rnyRxNDDgH4ogo5Mm+wrzEW6uFD2kdFI2IcSTx+RMu
3817A7n1/ZLCjqq6ZTXI3QZbWgr6AH3SOGM/lcnud4EROGUiZuTiWIBjxTy+q/8tA==
Decrypted string (expected): BadgeID^CustIDLookup^First Name^Last Name^Title^Company^Address 1^Address
2^City^State^Zip^Country^Phone^Email
Unfortunately without actually knowing how it has been encrypted, it seems that the decoding is not fully working.
I've created a category of NSString with the following method:
- (NSString *)decryptWithKey:(NSString *)key {
NSData *stringData = [self dataUsingEncoding:NSUTF8StringEncoding];
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
size_t decryptedDataLength = [stringData length] + kCCKeySizeAES128;
NSMutableData *decryptedData = [NSMutableData dataWithLength:kCCKeySizeAES128 + decryptedDataLength];
size_t numberOfBytes;
CCCryptorStatus status = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
[keyData bytes],
kCCKeySizeAES128,
nil,
[stringData bytes], [stringData length],
decryptedData.mutableBytes, [decryptedData length],
&numberOfBytes);
if (status == kCCSuccess) {
return [decryptedData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
} else {
NSLog(#"Status: %d", status);
return #"";
}
}
I get a kCCSuccess status but the string is not as expected. Any help will be greatly appreciated.
I think this generates random 64 bytes NSData.
uint8_t buffer[64];
SecRandomCopyBytes(kSecRandomDefault, 64, buffer);
NSData *keyData = [[NSData alloc] initWithBytes:buffer length:sizeof(buffer)];
I want to generate 64 bytes NSData like this but not a random data.
How can I generate 64 bytes NSData with a given key like "com.this.is.akey".
Tried this one but it gave me wrong bytes size(not 64 bytes).
NSString *base64EncodedString = [[#"somekey.here" dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0];
NSData *encodedData = [[NSData alloc] initWithBase64EncodedString:base64EncodedString
options:0];
You can use -[NSString dataUsingEncoding:] to convert NSString to NSData.
NSString *key = #"com.this.is.akey";
NSData *keyData = [key dataUsingEncoding:NSASCIIStringEncoding];
If length of the data is less or greater than 64 bytes, you should pad or truncate data to exact 64 bytes.
if (keyData.length != 64) {
NSMutableData *mutableData = keyData.mutableCopy;
mutableData.length = 64;
keyData = mutableData.copy;
}
Then, you can pass the NSData object to RLMRealmConfiguration.encryptionKey.
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.encryptionKey = keyData;
NSError *error = nil;
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
Given a string for a key one should use a key derivation function such as PBKDF2.
Example:
#import <CommonCrypto/CommonCrypto.h>
NSString *keyString = #"com.this.is.key"; // Should use a random value
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
NSData *salt = [#"saltstring" dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *derivedKey = [NSMutableData dataWithLength:CC_SHA512_DIGEST_LENGTH];
CCKeyDerivationPBKDF(kCCPBKDF2,
keyData.bytes, keyData.length,
salt.bytes, salt.length,
kCCPRFHmacAlgSHA512,
10000, // Choose for desired timing
derivedKey.mutableBytes, derivedKey.length);
NSLog(#"derivedKey: %#", derivedKey);
Output: derivedKey:
065d2106 1da7ebcf d155a50a b1ee5540 dee8efce f4678c47 02164488 e92e05e5 30c1f12d a3813013 652aca1b 0016b258 610d7929 f240de72 3eab85d9 7e028b35
Notes:
It is best to set the salt to a random value and provide it along with the derived key.
The iteration count should set to provide a suitable derivation tine, perhaps 100ms. There is a corresponding CCCalibratePBKDF function the help with this. The iteration count can also be provided along with the derived key.
Sorry if this seems to be more work that necessary but security is not easy to get right.
I am using the following code to write the 0xDE value for a Bluetooth Caracteristic (Reset Device) using the IOS Core Bluetooth :
...
NSData *bytes = [#"0xDE" dataUsingEncoding:NSUTF8StringEncoding];
[peripheral writeValue:bytes
forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];
...
is there any mistake in my code because the value is not written properly?
Swift 3.0: In case anyone is wondering the format for Swift is slightly different as writeValue can get the count from the array.
let value: UInt8 = 0xDE
let data = Data(bytes: [value])
peripheral.writeValue(data, for: characteristic, type: .withResponse)
Try creating your data with an array of single byte values.
const uint8_t bytes[] = {0xDE};
NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
This is a useful approach for creating arbitrary constant data. For more bytes,
const uint8_t bytes[] = {0x01,0x02,0x03,0x04,0x05};
NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
If you want to create data to send using variables, I would recommend using NSMutableData and appending the bytes that you need. It isn't very pretty, but it is easy to read / understand, especially when you are matching a packed struct on the embedded side. Example below is from a BLE project where we were making a simple communication protocol.
NSMutableData *data = [[NSMutableData alloc] init];
//pull out each of the fields in order to correctly
//serialize into a correctly ordered byte stream
const uint8_t start = PKT_START_BYTE;
const uint8_t bitfield = (uint8_t)self.bitfield;
const uint8_t frame = (uint8_t)self.frameNumber;
const uint8_t size = (uint8_t)self.size;
//append the individual bytes to the data chunk
[data appendBytes:&start length:1];
[data appendBytes:&bitfield length:1];
[data appendBytes:&frame length:1];
[data appendBytes:&size length:1];
The answer by bensarz is almost correct. Except one thing: you shouldn't use sizeof(int) as the length for NSData. The size of int is 4 or 8 bytes (depending on the architecture). As you want to send 1 byte, use uint8_t or Byte instead:
uint8_t byteToWrite = 0xDE;
NSData *data = [[NSData alloc] initWithBytes:&byteToWrite length:sizeof(&byteToWrite)];
[peripheral writeValue:data
forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];
Of courser you could also use int as the variable's type, but you have to initialize NSData with the length of 1.
This code will fix the problem :
NSData * data = [self dataWithHexString: #"DE"];
[peripheral writeValue:data forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];
dataWithHexString implementation :
- (NSData *)dataWithHexString:(NSString *)hexstring
{
NSMutableData* data = [NSMutableData data];
int idx;
for (idx = 0; idx+2 <= hexstring.length; idx+=2) {
NSRange range = NSMakeRange(idx, 2);
NSString* hexStr = [hexstring substringWithRange:range];
NSScanner* scanner = [NSScanner scannerWithString:hexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
return data;
}
What you are, in fact, doing here is writing the string "0xDE" to the characteristic. If you want to use binary/octal notation, you need to stay away from strings.
int integer = 0xDE;
NSData *data = [[NSData alloc] initWithBytes:&integer length:sizeof(integer)];
[peripheral writeValue:data
forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];
My code looks like this (using CommonCrypto/CommonHMAC.h):
- (NSString*) preperingCryptedData: (NSString*) data withKey: (NSString*) key {
NSData* dataToHash = [data dataUsingEncoding:NSUTF8StringEncoding];
NSData* keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"Utility: preperingCryptedData - Data to Crypt: %# and key %#\n...\n...\n...\n",dataToHash,keyData);
NSMutableData *dataHash = [NSMutableData dataWithLength:CC_SHA384_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA384, keyData.bytes, keyData.length, dataToHash.bytes, dataToHash.length, dataHash.mutableBytes);
NSString* readyString = [[NSString alloc] initWithData:dataToHash encoding:NSUTF8StringEncoding];
NSLog(#"Utility: preperingCryptedData call, result :%#\n...\n...\n...\n",readyString);
return readyString;
}
When I used code from: Here I got my string decoded without the Key. What am I doing wrong? How it's possible to encode message without the key?
There are two problem with the code:
1) You are using dataToHash as the output instead of dataHash.
2) dataHash is not a UTF8 data representation so it can not be successfully converted into a NSString.
Agree with the accepted answer. Provide working code.
- (NSString *)sha384:(NSString*)data withKey:(NSString *)key {
NSData* dataToHash = [data dataUsingEncoding:NSUTF8StringEncoding];
NSData* keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
unsigned char digest[CC_SHA384_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA384, keyData.bytes, keyData.length, dataToHash.bytes, dataToHash.length, digest);
NSString *sha384Str;
NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA384_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA384_DIGEST_LENGTH; i++)
[output appendFormat:#"%02x", digest[i]];
sha384Str = output;
return sha384Str;
}