I'm new to xCode and Objective-C. I've coded a QR-Scanner, now I need to decrypt the Data which is encryptet with AES128 CBC. I encrypt the plaintext using this snippet in php: http://www.androidsnippets.com/encrypt-decrypt-between-android-and-php
Could you help me pls? Sorry for my bad English, I'm German :D
Use CommonCrypto, See CommonCrypto and CCCryptor
Here is a snippit to get you started:
+ (NSData *)doCipher:(NSData *)dataIn
iv:(NSData *)iv
key:(NSData *)symmetricKey
context:(CCOperation)encryptOrDecrypt
error:(NSError **)error
{
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0; // Number of bytes moved to buffer.
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
ccStatus = CCCrypt( encryptOrDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
symmetricKey.bytes,
kCCKeySizeAES128,
iv.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
if (ccStatus == kCCSuccess) {
dataOut.length = cryptBytes;
}
else {
if (error) {
*error = [NSError errorWithDomain:#"kEncryptionError"
code:ccStatus
userInfo:nil];
}
dataOut = nil;
}
return dataOut;
}
Also see RNCryptor for a full implementation.
Related
I am planning to implement the AES encryption in my application and for this I went through an informative tutorial by Rob Napier :
It was a wonderful read and I was able to encrypt few strings using :
USING ROB NAPIER RNCRYPTOR CLASS
NSString * const
kRNCryptManagerErrorDomain = #"net.robnapier.RNCryptManager";
const CCAlgorithm kAlgorithm = kCCAlgorithmAES128;
const NSUInteger kAlgorithmKeySize = kCCKeySizeAES128;
const NSUInteger kAlgorithmBlockSize = kCCBlockSizeAES128;
const NSUInteger kAlgorithmIVSize = kCCBlockSizeAES128;
const NSUInteger kPBKDFSaltSize = 8;
const NSUInteger kPBKDFRounds = 10000; // ~80ms on an iPhone 4
// ===================
+ (NSData *)encryptedDataForData:(NSData *)data
password:(NSString *)password
iv:(NSData **)iv
salt:(NSData **)salt
error:(NSError **)error {
NSAssert(iv, #"IV must not be NULL");
NSAssert(salt, #"salt must not be NULL");
*iv = [self randomDataOfLength:kAlgorithmIVSize];
*salt = [self randomDataOfLength:kPBKDFSaltSize];
NSData *key = [self AESKeyForPassword:password salt:*salt];
size_t outLength;
NSMutableData *
cipherData = [NSMutableData dataWithLength:data.length +
kAlgorithmBlockSize];
CCCryptorStatus
result = CCCrypt(kCCEncrypt, // operation
kAlgorithm, // Algorithm
kCCOptionPKCS7Padding, // options
key.bytes, // key
key.length, // keylength
(*iv).bytes,// iv
data.bytes, // dataIn
data.length, // dataInLength,
cipherData.mutableBytes, // dataOut
cipherData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result == kCCSuccess) {
cipherData.length = outLength;
}
else {
if (error) {
*error = [NSError errorWithDomain:kRNCryptManagerErrorDomain
code:result
userInfo:nil];
}
return nil;
}
return cipherData;
}
// ===================
+ (NSData *)randomDataOfLength:(size_t)length {
NSMutableData *data = [NSMutableData dataWithLength:length];
int result = SecRandomCopyBytes(kSecRandomDefault,
length,
data.mutableBytes);
NSAssert(result == 0, #"Unable to generate random bytes: %d",
errno);
return data;
}
// ===================
// Replace this with a 10,000 hash calls if you don't have CCKeyDerivationPBKDF
+ (NSData *)AESKeyForPassword:(NSString *)password
salt:(NSData *)salt {
NSMutableData *
derivedKey = [NSMutableData dataWithLength:kAlgorithmKeySize];
int
result = CCKeyDerivationPBKDF(kCCPBKDF2, // algorithm
password.UTF8String, // password
[password lengthOfBytesUsingEncoding:NSUTF8StringEncoding], // passwordLength
salt.bytes, // salt
salt.length, // saltLen
kCCPRFHmacAlgSHA1, // PRF
kPBKDFRounds, // rounds
derivedKey.mutableBytes, // derivedKey
derivedKey.length); // derivedKeyLen
// Do not log password here
NSAssert(result == kCCSuccess,
#"Unable to create AES key for password: %d", result);
return derivedKey;
}
But while decrypting I am not able to decrypt properly and I am getting null in the scenario: For your reference the decrypt code is :
+ (NSData*)decryptData:(NSData*)data key:(NSData*)key error:(NSError **)error
{
if (key.length != 16 && key.length != 24 && key.length != 32) {
*error = [NSError errorWithDomain:#"keyLengthError" code:-1 userInfo:nil];
return nil;
}
CCCryptorStatus ccStatus = kCCSuccess;
int ivLength = kCCBlockSizeAES128;
size_t clearBytes = 0;
NSMutableData *dataOut = [NSMutableData dataWithLength:data.length - ivLength];
NSLog(#"Data Out String Decrypt%#", dataOut);
ccStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
key.bytes,
key.length,
data.bytes,
data.bytes + ivLength,
data.length - ivLength,
dataOut.mutableBytes,
dataOut.length,
&clearBytes);
if (ccStatus == kCCSuccess) {
dataOut.length = clearBytes;
}
else {
if (error) {
*error = [NSError errorWithDomain:#"kEncryptionError" code:ccStatus userInfo:nil];
}
dataOut = nil;
}
return dataOut;
}
Where I am getting wrong in this scenario? I have been trying for few days to sort it out. Can someone please help me?
the method given in the example you mentioned refers Rob Napiers Github Repo.
Just testet it with your given password, salt, etc.. and it just works!
Yes understood, you want to throw out password: and iv: as well the salt: parameter when decrypting and go only with key:. Well you need at least iv: to do that. But again as Rob commented to your other question, don't re-invent the wheel.
The method i linked above is just working fine with your parameters for decrypting. The only difference to your code is that password, iv and salt are given to decrypt.
apart from the idea you want to develop something that can decrypt without a password you will have to digg deeper into how CCKeyDerivationPBKDF() (CommonKeyDerivation.h) is working.
Edit: As you asked to have a way to pack and unpack your salt, iv and cypher thats pretty simple with NSData.
+ (NSData *)packWithSalt:(NSData*)salt IV:(NSData*)iv Cypher:(NSData*)tocypher {
//adding Salt + IV + Cipher text
NSMutableData *combi = [NSMutableData data];
//[combi appendBytes:salt.bytes length:16];
//[combi appendBytes:iv.bytes length:16]; //16
//[combi appendBytes:tocypher.bytes length:tocypher.length];
[combi appendData:salt];
[combi appendData:iv];
[combi appendData:tocypher];
return combi;
}
+ (NSData*)cypherUnpackToSalt:(NSMutableData**)salt andIV:(NSMutableData**)iv fromPackData:(NSData*)pack {
void *sBuff[16] = {};
void *iBuff[16] = {};
NSUInteger len = pack.length - 16 - 16; //keep length flexible
void *pBuff = malloc(sizeof(Byte)*len); //needs dynamically size of buff
[pack getBytes:sBuff range:NSMakeRange(0, 16)];
[pack getBytes:iBuff range:NSMakeRange(16, 32)];
[pack getBytes:pBuff range:NSMakeRange(32, len)];
[(*salt) replaceBytesInRange:NSMakeRange(0, 16) withBytes:sBuff];
[(*iv) replaceBytesInRange:NSMakeRange(0, 16) withBytes:iBuff];
NSMutableData *unpack = [NSMutableData dataWithLength:len];
[unpack replaceBytesInRange:NSMakeRange(0, len) withBytes:pBuff];
free(pBuff);
return unpack;
}
it should be pretty simple to integrate the encryption and decryption from these two methods.
Proof of concept: Can we pack all together? and Unpack again?
NSData *salt = [CryptAES randomDataOfLength:16];
NSData *iv = [CryptAES randomDataOfLength:16];
NSData *chunk = [CryptAES packWithSalt:salt IV:iv Cypher:plaintextData];
NSLog(#"salt=%# iv=%# pack=%# ",[salt base64EncodedStringWithOptions:0], [iv base64EncodedStringWithOptions:0], [chunk base64EncodedStringWithOptions:0] );
NSMutableData *unSalt = [NSMutableData dataWithLength:16];
NSMutableData *unIv = [NSMutableData dataWithLength:16];
NSData *unchunk = [CryptAES cypherUnpackToSalt:&unSalt andIV:&unIv fromPackData:chunk];
NSString *plainAgain = [[NSString alloc] initWithData:unchunk encoding:NSUTF8StringEncoding];
NSLog(#"salt=%# iv=%# unpack=%#",[unSalt base64EncodedStringWithOptions:0], [unIv base64EncodedStringWithOptions:0], plainAgain );
So your decryption method will still need parameters for a password.
Which is not perfect but as you should never throw around encrypted data together with its password - that should be ok - you just keep the handling of a password on the user side. I mean otherwise the whole encryption is useless!
I am very new in iOS app developing. I need to encrypt and decrypt the files in ios using objective-c. While i am searching i got string encrypt and decrypt only.
CCCryptorStatus status = CCCrypt(kCCDecrypt,/* kCCEncrypt, etc. */
kCCAlgorithmAES128, /* kCCAlgorithmAES128, etc. */
kCCOptionPKCS7Padding, /* kCCOptionPKCS7Padding, etc. */
keyPointer, kCCKeySizeAES256,/* key and its length */
ivPointer, /* initialization vector - use same IV which was used for decryption */
[encryptedText bytes], [encryptedText length], //input
buff, buffSize,//output
&numBytesEncrypted);
Here how can i encrypt and decrypt the files. Thanks
Finally i got the solution for file encrypt and decrypt using AES. I maintain same code for both encrypt and decrypt for files using crypt type. if we pass the crypttype as 1 the file encrypt using aes. If we do decrypt we can pass the value as 2.
FileAes.m
RCT_EXPORT_METHOD(encryptDecryptFile:(NSString *)crypType
appkey:(NSString *)key
inputPath:(NSString *)inputPath
outPutPath : (NSString *)outputPath
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
if ([[SecurityUtil encryptDecryptAESFile:crypType app_key:key input_path:inputPath output_path:outputPath] length] <= 0) {
reject(#"ERROR", #"decrypt failed", nil);
}
resolve ([SecurityUtil encryptDecryptAESFile:crypType app_key:key input_path:inputPath output_path:outputPath]);
}
SecurityUtil.m
+(NSString*)encryptDecryptAESFile:(NSString*)cryptType app_key:(NSString*)key input_path:(NSString*)inputPath output_path:(NSString *)outputPath
{
NSLog(#"file input path===> %#",cryptType);
NSString *res;
NSData *decryedData;
#try {
NSData *data = [NSData dataWithContentsOfFile:inputPath];
if(cryptType == #"1"){
decryedData = [data AES128EncryptFileWithKey:key ];
}else{
decryedData = [data AES128DecryptFileWithKey:key ];
}
//NSData *decryedData = [data AES128DecryptFileWithKey:key gIv:key];
[decryedData writeToFile:outputPath atomically:YES];
res =#"success";
return res;
}
#catch (NSException *exception) {
NSLog(#"Exception in decrypt File==> %#", exception.reason);
res=#"failure";
return res;
}
#finally {
NSLog(#"Finally condition=== %#",res);
return res;
}
}
NSDataAesFile.m
- (NSData *)AES128DecryptFileWithKey:(NSString *)key {//FileDecrypt
char keyPtr[kCCKeySizeAES128+1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
char ivPtr[kCCKeySizeAES128+1];
memset(ivPtr, 0, sizeof(ivPtr));
[key getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];//gIv
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
keyPtr,
kCCBlockSizeAES128,
ivPtr,
[self bytes],
dataLength,
buffer,
bufferSize,
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
NSLog(#"crypt status==> %d", cryptStatus);
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer);
return nil;
}
The above code is working for me. May be it will help.
I'm not an expert about this at all, so I've found a wrapper on github called RSA and tried to use it.
What I need to do is simply encrypt a string using my private key.
This is the method used to do the encryption:
- (NSString *)rsaEncryptWithData:(NSData*)data usingPublicKey:(BOOL)yes {
if (yes) {
[self getKeyRefFor:publicTag];
} else {
[self getKeyRefFor:privateTag];
}
}
SecKeyRef key = self.publicKeyRef;
size_t cipherBufferSize = SecKeyGetBlockSize(key);
uint8_t *cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
memset((void *)cipherBuffer, 0*0, cipherBufferSize);
NSData *plainTextBytes = data;
size_t blockSize = cipherBufferSize - 11;
size_t blockCount = (size_t)ceil([plainTextBytes length] / (double)blockSize);
NSMutableData *encryptedData = [NSMutableData dataWithCapacity:0];
for (int i=0; i<blockCount; i++) {
int bufferSize = (int)MIN(blockSize,[plainTextBytes length] - i * blockSize);
NSData *buffer = [plainTextBytes subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];
OSStatus status = SecKeyEncrypt(key,
kSecPaddingPKCS1,
(const uint8_t *)[buffer bytes],
[buffer length],
cipherBuffer,
&cipherBufferSize);
if (status == noErr){
NSData *encryptedBytes = [NSData dataWithBytes:(const void *)cipherBuffer length:cipherBufferSize];
[encryptedData appendData:encryptedBytes];
}else{
if (cipherBuffer) {
free(cipherBuffer);
}
return nil;
}
}
if (cipherBuffer) free(cipherBuffer);
return [encryptedData base64EncodedStringWithOptions:0];
}
If I use my public key to encrypt, everything is working fine, but if I try to use my private key then the OSStatus variable returns a -4 (Function or operation not implemented.).
Any help would be really appreciated, since I really don't know what to do.
Thanks.
I ended up using the MIHCrypto framework to create a key pair and to sign my messages.
Is this easy:
- (NSData *)signMessageData:(NSData *)data withKey:(MIHRSAPrivateKey *)privKey {
NSError *signingError = nil;
NSData *signatureData = [privKey signWithSHA256:data error:&signingError];
if (signingError != nil) {
NSLog(#"Error: %#", signingError.localizedDescription);
}
return signatureData;
}
I have googled a lot but enable to get Blowfish ECB algorithm with PKCS5 padding in Objective-C.
I have tried code from here but it is not giving me proper encrypted data. Even I have tried codes from here but it is not with PKSC5 padding.
Unfortunately I have to use Blowfish (no other option) to convert following JAVA code in Objective-C
String objVal=<the json>;
SecretKeySpec lKeySpec = new SecretKeySpec(lKey.getBytes("UTF8"),"Blowfish");
Cipher lCipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
lCipher.init(Cipher.ENCRYPT_MODE, lKeySpec);
byte[] lPassword = objVal.getBytes("UTF8");
byte[] lEncryptPassword = lCipher.doFinal(lPassword);
String lEncryptString = new BASE64Encoder().encode(lEncryptPassword);
StringBuffer nString = new StringBuffer();
for (int i = 0; i < lEncryptString.length(); i++) {
int a = lEncryptString.charAt(i);
if (a != 13 && a != 10 && !lEncryptString.substring(i, i + 1).equals(" ")){
nString.append(lEncryptString.charAt(i));
}
return nString.toString();
Then the encrypted json is encoded:
String returnData=<encrypted json>
byte[] inputBytes = returnData.getBytes();
returnData = DatatypeConverter.printBase64Binary(inputBytes);
Any one has tried and tested solution for Blowfish ECB algorithm with PKSC5 padding.
Thank you in advance.
I know this question is already (several times) asked but either not answered or not with PKCS5 padding
Example code:
Add Security.framework
#import <CommonCrypto/CommonCryptor.h>
+ (NSData *)doBlowfish:(NSData *)dataIn
context:(CCOperation)kCCEncrypt_or_kCCDecrypt
key:(NSData *)key
options:(CCOptions)options
iv:(NSData *)iv
error:(NSError **)error
{
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0;
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeBlowfish];
ccStatus = CCCrypt( kCCEncrypt_or_kCCDecrypt,
kCCAlgorithmBlowfish,
options,
key.bytes,
key.length,
(iv)?nil:iv.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
if (ccStatus == kCCSuccess) {
dataOut.length = cryptBytes;
}
else {
if (error) {
*error = [NSError errorWithDomain:#"kEncryptionError"
code:ccStatus
userInfo:nil];
}
dataOut = nil;
}
return dataOut;
}
Test:
NSError *error;
NSData *key = [#"Blowfish" dataUsingEncoding:NSUTF8StringEncoding];
NSString *stringOriginal = #"TestData";
NSData *dataOriginal = [stringOriginal dataUsingEncoding:NSUTF8StringEncoding];;
NSLog(#"key %#", key);
NSLog(#"stringOriginal %#", stringOriginal);
NSLog(#"dataOriginal %#", dataOriginal);
NSData *dataEncrypted = [Test doBlowfish:dataOriginal
context:kCCEncrypt
key:key
options:kCCOptionPKCS7Padding | kCCOptionECBMode
iv:nil
error:&error];
NSLog(#"dataEncrypted %#", dataEncrypted);
NSString *encryptedBase64String = [dataEncrypted base64EncodedStringWithOptions:0];
NSLog(#"encryptedBase64String %#", encryptedBase64String);
NSData *dataToDecrypt = [[NSData alloc] initWithBase64EncodedString:encryptedBase64String options:0];
NSData *dataDecrypted = [Test doBlowfish:dataToDecrypt
context:kCCDecrypt
key:key
options:kCCOptionPKCS7Padding | kCCOptionECBMode
iv:nil
error:&error];
NSLog(#"dataDecrypted %#", dataDecrypted);
NSString *stringDecrypted = [[NSString alloc] initWithData:dataDecrypted encoding:NSUTF8StringEncoding];
NSLog(#"stringDecrypted %#", stringDecrypted);
Output:
key 426c6f77 66697368
stringOriginal TestData
dataOriginal 54657374 44617461
dataEncrypted ba5eb956 7e73ae1a b5513ea1 75a14019
encryptedBase64String ul65Vn5zrhrdmeYV9B5rQA==
dataDecrypted 54657374 44617461
stringDecrypted TestData
Here is the code:
- (NSData *) doCipher: (NSData *) plainData key: (NSData *) symmetricKey context: (CCOperation) encryptOrDecrypt padding: (CCOptions *) pkcs7
{
// Initialization vector; dummy in this case 0's.
uint8_t iv[kChosenCipherBlockSize];
bzero((void *) iv, (size_t) sizeof(iv));
// We don't want to toss padding on if we don't need to
if (encryptOrDecrypt == kCCEncrypt)
{
if (*pkcs7 != kCCOptionECBMode)
{
if ((plainData.length % kChosenCipherBlockSize) == 0)
*pkcs7 = 0x0000;
else
*pkcs7 = kCCOptionPKCS7Padding;
}
}
else if (encryptOrDecrypt == kCCDecrypt)
{
*pkcs7 = 0x0000;
}
else
{
DLog(#"Invalid CCOperation parameter [%d] for cipher context.", *pkcs7);
return nil;
}
// Actually perform the encryption or decryption.
NSMutableData *dataOut = [NSMutableData dataWithLength: plainData.length + kChosenCipherBlockSize];
size_t movedBytes = 0;
CCCryptorStatus ccStatus = CCCrypt(encryptOrDecrypt,
kCCAlgorithmAES128,
*pkcs7,
symmetricKey.bytes,
kChosenCipherKeySize,
iv,
[plainData bytes],
[plainData length],
[dataOut mutableBytes],
[dataOut length],
&movedBytes
);
if (ccStatus == noErr)
{
dataOut.length = movedBytes;
}
else
{
DLog(#"Problem with encipherment ccStatus == %d", ccStatus);
return nil;
}
return dataOut;
}
When I using kCCOptionPKCS7Padding on kCCDecrypt sometimes I get error code 4304.
I try not using padding when kCCDecrypt as described here Anyone else having trouble with iOS 5 encryption?
and I don't get the error. But sometimes the data length after kCCDecrypt is not the same as original data length before kCCEncrypt. I think this is because original data length is not multiplied by encoding block size.
Anyone else have this trouble?
You cannot just toss out padding. Leave padding on and everything will be alright.
See also: Encrypting 16 bytes of UTF8 with SecKeyWrapper breaks (ccStatus == -4304)