3DES encryption using CFB8 and no padding in iOS? - ios

I am developing an application which will send encrypted data to a server. The server uses 3des with CFB8 and no padding. I have read most of the related questions in stackoverflow but still unable to get it work. Been working on this for few days but still unable to get it to match with the server encryption. here is what i have tried-
+ (NSString*) doCipher:(NSString*)plainText operation:(CCOperation)encryptOrDecrypt {
const void *vplainText;
NSData* plainTextData;
size_t plainTextBufferSize;
if (encryptOrDecrypt == kCCDecrypt)
{
NSData *EncryptData =[NSData dataWithBase64EncodedString:plainText];
plainTextBufferSize = [EncryptData length];
vplainText = [EncryptData bytes];
}
else
{
plainTextData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
plainTextBufferSize = [plainTextData length];
}
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
uint8_t iv[kCCBlockSize3DES];
bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x0, bufferPtrSize);
memset((void *) iv, 0x0, (size_t) sizeof(iv));
const void *vkey = kPrivateKey;
unsigned char IV[8]={0,0,0,0,0,0,0,0};
ccStatus = CCCrypt(encryptOrDecrypt,
kCCAlgorithm3DES,
0,
[keyData bytes],
[key length],
IV,
[plainTextData bytes],
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
&movedBytes);
if (ccStatus == kCCSuccess) NSLog(#"SUCCESS");
else if (ccStatus == kCCParamError) return #"PARAM ERROR";
else if (ccStatus == kCCBufferTooSmall) return #"BUFFER TOO SMALL";
else if (ccStatus == kCCMemoryFailure) return #"MEMORY FAILURE";
else if (ccStatus == kCCAlignmentError) return #"ALIGNMENT";
else if (ccStatus == kCCDecodeError) return #"DECODE ERROR";
else if (ccStatus == kCCUnimplemented) return #"UNIMPLEMENTED";
NSString *result;
if (encryptOrDecrypt == kCCDecrypt)
{
result = [[NSString alloc] initWithData: [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes] encoding:NSASCIIStringEncoding];
}
else
{
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
result = [myData base64EncodedString];
}
return result;
}
It seems CCOptions currently supports kCCOptionPKCS7Padding and kCCOptionECBMode.How to achieve 3des with CFB8 and no padding.Any suggestion would be appreciated.

EDIT: Sorry; I overlooked a key point previously. You're never asking for CFB8 mode. The default is CBC mode.
You can't use CCCrypt() for this. You have to use CCCryptorCreateWithMode() so you can pass the mode. Then call CCCryptorUpdate() with the data and CCCryptorFinal() to finish.
If you don't want padding, why are you requesting padding? Remove kCCOptionPKCS7Padding. If you don't want any options (which you appear not to), just pass 0.
CFB-8 takes an initialization vector. You've set it to all 0's. Is this what the server is using? (This is a very poor IV; the IV for CFB should be random, not fixed.)
These lines are dangerous:
plainTextBufferSize = [plainText length];
vplainText = (const void *) [plainText UTF8String];
This will truncate any multi-byte strings. The better solution to this is to create an NSData:
plainTextData = [self.plainText dataUsingEncoding:NSUTF8StringEncoding];
You can then use bytes and length on plainTextData.

Related

Objective c RSA with OAEP padding sha256 prior ios 10

I am working on an encryption method in the iPhone with the RSA encryption method, so far i could achieve getting the encryption string with this method, the string is successfully decrypted by the server.
SecKeyRef keyRef = [self addPublicKey:pubKey];
SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA256;
if (!keyRef) {
return nil;
}
BOOL canEncrypt = SecKeyIsAlgorithmSupported(keyRef, kSecKeyOperationTypeEncrypt, algorithm);
if (canEncrypt) {
CFErrorRef error = NULL;
NSData *encryptedData = (NSData *)CFBridgingRelease(
SecKeyCreateEncryptedData(keyRef, algorithm, (__bridge CFDataRef) content, &error)
);
if (encryptedData) {
return encryptedData;
}else{
NSError *err = CFBridgingRelease(error);
NSLog(#"OcurriĆ³ un error %#", err.localizedDescription);
return nil;
}
}
This method works for ios 10 and newer, what i need is to know how to set the algorithm in prior ios versions, my code is the following
SecKeyRef keyRef = [self addPublicKey:pubKey];
if (!keyRef) {
return nil;
}
size_t cipherBufferSize = SecKeyGetBlockSize(keyRef);
uint8_t *cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
memset((void *)cipherBuffer, 0*0, cipherBufferSize);
NSData *plainTextBytes = content;
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(keyRef,
kSecPaddingOAEP,
(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);
So far i can see that in the version of ios 10 you can set the algorithm with this line
SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA256;
my question is, how do i get that algorithm in the early version of ios, the second code i post can't be decrypted.
Thanks for your help
If you are using OAEP padding with SecKeyEncrypt, you can only use kSecPaddingOAEP, which is SHA1. Unfortunately you cannot use OAEP SHA256 with SecKeyEncrypt.

AES/cbc/pkcs5padding encription IOS

I have used AES algorithm for encryption in android.
The following code we have used for encryption.
String seed = "somekey";
Key key = null;
// 128 bit key
byte[] byteKey = seed.substring(0, 16).getBytes("UTF-8");
key = new SecretKeySpec(byteKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(
new byte[16]));
byte[] encValue = cipher.doFinal(pValue.getBytes());
encryptedText = new BASE64Encoder().encode(encValue);
Can any one please provide the above logic for IOS.
Thanking in Advance.
It works both on android with:
#define FBENCRYPT_KEY_SIZE kCCKeySizeAES128
instead:
#define FBENCRYPT_KEY_SIZE kCCKeySizeAES256
You can use the following snippet as start point:
+ (NSData*)encryptData:(NSData*)data key:(NSData*)key iv:(NSData*)iv;
{
NSData* result = nil;
// setup key
unsigned char cKey[FBENCRYPT_KEY_SIZE];
bzero(cKey, sizeof(cKey));
[key getBytes:cKey length:FBENCRYPT_KEY_SIZE];
// setup iv
char cIv[FBENCRYPT_BLOCK_SIZE];
bzero(cIv, FBENCRYPT_BLOCK_SIZE);
if (iv) {
[iv getBytes:cIv length:FBENCRYPT_BLOCK_SIZE];
}
// setup output buffer
size_t bufferSize = [data length] + FBENCRYPT_BLOCK_SIZE;
void *buffer = malloc(bufferSize);
// do encrypt
size_t encryptedSize = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
FBENCRYPT_ALGORITHM,
kCCOptionPKCS7Padding,
cKey,
FBENCRYPT_KEY_SIZE,
cIv,
[data bytes],
[data length],
buffer,
bufferSize,
&encryptedSize);
if (cryptStatus == kCCSuccess) {
result = [NSData dataWithBytesNoCopy:buffer length:encryptedSize];
} else {
free(buffer);
NSLog(#"[ERROR] failed to encrypt|CCCryptoStatus: %d", cryptStatus);
}
return result;
}
+ (NSData*)decryptData:(NSData*)data key:(NSData*)key iv:(NSData*)iv;
{
NSData* result = nil;
// setup key
unsigned char cKey[FBENCRYPT_KEY_SIZE];
bzero(cKey, sizeof(cKey));
[key getBytes:cKey length:FBENCRYPT_KEY_SIZE];
// setup iv
char cIv[FBENCRYPT_BLOCK_SIZE];
bzero(cIv, FBENCRYPT_BLOCK_SIZE);
if (iv) {
[iv getBytes:cIv length:FBENCRYPT_BLOCK_SIZE];
}
// setup output buffer
size_t bufferSize = [data length] + FBENCRYPT_BLOCK_SIZE;
void *buffer = malloc(bufferSize);
// do decrypt
size_t decryptedSize = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
FBENCRYPT_ALGORITHM,
kCCOptionPKCS7Padding,
cKey,
FBENCRYPT_KEY_SIZE,
cIv,
[data bytes],
[data length],
buffer,
bufferSize,
&decryptedSize);
if (cryptStatus == kCCSuccess) {
result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
} else {
free(buffer);
NSLog(#"[ERROR] failed to decrypt| CCCryptoStatus: %d", cryptStatus);
}
return result;
}
Constants
#define FBENCRYPT_ALGORITHM kCCAlgorithmAES128
#define FBENCRYPT_BLOCK_SIZE kCCBlockSizeAES128
#define FBENCRYPT_KEY_SIZE kCCKeySizeAES256
For more information, see FBEncryptor
Hope this helps.
Since AES has a bock size of 16-bytes PKCS#7Padding is required. Some earlier AES library implementers specified PKCS#5Padding in error.
PKCS#5Padding is only specified for a block size up to 8-bytes and PKCS#7Padding is specified for a block size up to 255-bytes. See Wikipedia: Padding. IOW PKCS#7Padding can be used in place of PKCS#5Padding.

EXC_BAD_ACCESS Code 2 on CCCrypt

I am trying to use DES encryption to encrypt passwords (Don't ask why DES, I know it's less secure). I am doing it for the first time in iOS, thus had to rely on another post about how to do it.
When I run the encryption it returns null, same with decrypting an already encrypted string(I used an online tool to encrypt). When I put a breakpoint to see what is going on, it stopped at CCCrypt mentioning EXC_BAD_ACCESS (Code 2).
I tried using different CCOptions, but it returns the same thing always.
Any hint what's going wrong? Is iv string required?
I have used the following NSString category to encrypt or decrypt Strings -
#import "NSString+DES.h"
#implementation NSString(DES)
- (NSString*) encryptDES: (NSString *) key
{
const void *vplainText;
size_t plainTextBufferSize;
plainTextBufferSize = [self length];
vplainText = (const void *) [self UTF8String];
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t *movedBytes;
bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x0, bufferPtrSize);
// memset((void *) iv, 0x0, (size_t) sizeof(iv));
//NSString *initVec = #"init Vec";
const void *vkey = (const void *) [key UTF8String];
//const void *vinitVec = (const void *) [initVec UTF8String];
ccStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding | kCCOptionECBMode,
vkey,
kCCKeySizeDES,
NULL,
vplainText,
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
movedBytes);
NSString *result;
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
result = [myData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
return result;
}
- (NSString *) decryptDES: (NSString *) key
{
const void *vplainText;
size_t plainTextBufferSize;
plainTextBufferSize = [self length];
vplainText = (const void *) [self UTF8String];
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t *movedBytes;
bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x0, bufferPtrSize);
// memset((void *) iv, 0x0, (size_t) sizeof(iv));
//NSString *initVec = #"init Vec";
const void *vkey = (const void *) [key UTF8String];
//const void *vinitVec = (const void *) [initVec UTF8String];
ccStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding | kCCOptionECBMode,
vkey, //"123456789012345678901234", //key
kCCKeySizeDES,
NULL,// vinitVec, //"init Vec", //iv,
vplainText, //"Your Name", //plainText,
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
movedBytes);
NSString *result;
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
result = [myData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
return result;
}
#end
Update:
I have checked few more places and changed the code a little bit, the encryption works but doesn't get decrypted with correct value.
For example when I use YourName as string and 12345 as the key, I get Fu2sK61e7l5rkXRhAKjPWA== as the encrypted code, but the decryption returns +54qWCYTB5LkdARDZjAow== and not YourName.
Updated Code:
#import "NSString+DES.h"
#implementation NSString(DES)
- (NSString*) encryptDES: (NSString *) key
{
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
NSData *stringData = [self dataUsingEncoding:NSUTF8StringEncoding];
size_t numBytesEncrypted = 0;
size_t bufferSize = stringData.length + kCCBlockSizeDES;
void *buffer = malloc(bufferSize);
CCCryptorStatus result = CCCrypt( kCCEncrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding,
keyData.bytes, kCCKeySizeDES,
NULL,
stringData.bytes, stringData.length,
buffer, bufferSize,
&numBytesEncrypted);
NSData *output = [NSData dataWithBytes:buffer length:numBytesEncrypted];
free(buffer);
if( result == kCCSuccess )
{
NSString *resultStr = [output base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
return resultStr;
} else {
NSLog(#"Failed DES encrypt...");
return nil;
}
}
- (NSString *) decryptDES: (NSString *) key
{
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
NSData *stringData = [[NSData alloc] initWithBase64EncodedString:self options:0];
size_t numBytesEncrypted = 0;
size_t bufferSize = stringData.length + kCCBlockSizeDES;
void *buffer = malloc(bufferSize);
CCCryptorStatus result = CCCrypt( kCCDecrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding,
keyData.bytes, kCCKeySizeDES,
NULL,
stringData.bytes, stringData.length,
buffer, bufferSize,
&numBytesEncrypted);
NSData *output = [NSData dataWithBytes:buffer length:numBytesEncrypted];
free(buffer);
if( result == kCCSuccess )
{
NSString *resultStr = [output base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
return resultStr;
} else {
NSLog(#"Failed DES decrypt...");
return nil;
}
}
#end
There seems to be general confusion about the algorithm, DES or 3DES, a mix is being used but the key is 3DES (24-bytes). The key needs to be changed to 8-bytes. The block size constant should also be changed to kCCBlockSizeDES but that does not cause an error since it is the same value.
For the method:
- (NSString *) decryptDES: (NSString *) key
The bad access error is caused because no storage is allocated for movedBytes, just a pointer. Change the declaration to:
size_t movedBytes;
Change the reference to movedBytes in CCCrypt to &movedBytes.
Test output for encryption:
string: "Your Name"
key: "12345678"
movedBytes: 16
myData: 136142f6 6cd98e01 af1eef46 28d36499
result: E2FC9mzZjgGvHu9GKNNkmQ==
Notes from comments by request:
ECB mode does not use an iv.
The key needs to be exactly 8-bytes for DES, if it is to short the result will be undefined. In the updated code the key is 5-bytes but the length is given as 8-bytes (kCCKeySizeDES) so the three missing key bytes will be whatever bytes follow keyData.
The updated answer did not specify ECB mode, the default is CBC mode. Add kCCOptionECBMode.
In decrypt do not use Base64 encode, convert the data to a NSString:
NSString * resultStr = [[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding];
If using an online encryption that uses the php mcrypt function the last block of the data will be incorrect because mcrypt does not support PKCS#7 padding, it uses non-standard and insecure null padding.

3DES encryption in iOS does not seem to encrypt last block

I have the following code in objective-c
NSString* v_plainText = #"1234567890123456789012345678";
NSString* plainText = (const void *) [v_plainText UTF8String];
size_t plainTextBufferSize = [v_plainText length];
size_t bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
size_t movedBytes = 0;
uint8_t *bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
Byte iv[8] = {0,0,0,0,0,0,0,0};
NSString *key = (const void *) [#"12345678ABCDEFGH!##$%^&*" UTF8String];
CCCryptorStatus ccStatus;
ccStatus = CCCrypt(kCCEncrypt,
kCCAlgorithm3DES,
kCCOptionPKCS7Padding & kCCModeCBC,
key,
kCCKeySize3DES,
iv,
plainText,
plainTextBufferSize,
(void *)bufferPtr, // output
bufferPtrSize,
&movedBytes);
NSData* result = [NSData dataWithBytes:(const void*)bufferPtr length:(NSUInteger)movedBytes];
NSString* str = [result base64EncodedStringWithOptions:0];
This gives this result:
geHFnvoept2aKiruo6InSvc7WVPdHNq2
When I run simular code in .NET it gives me this result:
geHFnvoept2aKiruo6InSvc7WVPdHNq2TENQX5q9Beg=
For some reason the objective-c version only returns 24 bytes while the input is 28 bytes. I would expect it to be 32 bytes like in the .NET version. I was unable to determine what I'm doing wrong here.
The encryption error is:
kCCOptionPKCS7Padding & kCCModeCBC,
You need |, not & but kCCModeCBC is not a valid option and no option is needed because CBC is the default mode, you simply need:
kCCOptionPKCS7Padding,
Unfortunatly there are other objectiveC coding errors, mainly:
NSString* plainText = (const void *) [v_plainText UTF8String];
NSString *key = (const void *) [#"12345678ABCDEFGH!##$%^&*" UTF8String];
Instead use:
NSData* plainText = [v_plainText dataUsingEncoding:NSUTF8StringEncoding];
NSData *key = [#"12345678ABCDEFGH!##$%^&*" dataUsingEncoding:NSUTF8StringEncoding];
Here is the complete code converted to use NSData:
NSString* plainText = #"1234567890123456789012345678";
NSString* keyText = #"12345678ABCDEFGH!##$%^&*";
NSData* plainData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
NSData *keyData = [keyText dataUsingEncoding:NSUTF8StringEncoding];
Byte iv[8] = {0,0,0,0,0,0,0,0};
size_t bufferSize = plainData.length + kCCBlockSize3DES;
NSMutableData *cypherData = [NSMutableData dataWithLength:bufferSize];
size_t movedBytes = 0;
CCCryptorStatus ccStatus;
ccStatus = CCCrypt(kCCEncrypt,
kCCAlgorithm3DES,
kCCOptionPKCS7Padding,
keyData.bytes,
kCCKeySize3DES,
iv,
plainData.bytes,
plainData.length,
cypherData.mutableBytes,
cypherData.length,
&movedBytes);
cypherData.length = movedBytes;
NSString* str = [cypherData base64EncodedStringWithOptions:0];
NSLog(#"str: %#", str);
Oputput:
str: geHFnvoept2aKiruo6InSvc7WVPdHNq2TENQX5q9Beg=

Why am I getting different results each time I try to decrypt AES data with the iOS SDK?

I am working on AES encryption and decryption.
I am giving single data and single key to decrypt but am getting different outputs every time.
I am using like this:
+(NSData*)decryptData:(NSData*)data key:(NSData*)key iv:(NSData*)iv
{
NSData* result = nil;
// setup key
unsigned char cKey[FBENCRYPT_KEY_SIZE];
bzero(cKey, sizeof(cKey));
[key getBytes:cKey length:FBENCRYPT_KEY_SIZE];
// setup iv
char cIv[FBENCRYPT_BLOCK_SIZE];
bzero(cIv, FBENCRYPT_BLOCK_SIZE);
if (iv) {
[iv getBytes:cIv length:FBENCRYPT_BLOCK_SIZE];
}
// setup output buffer
size_t bufferSize = [data length] + FBENCRYPT_BLOCK_SIZE;
void *buffer = malloc(bufferSize);
// do decrypt
size_t decryptedSize = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
FBENCRYPT_ALGORITHM,
kCCOptionECBMode,
cKey,
FBENCRYPT_KEY_SIZE,
cIv,
[data bytes],
[data length],
buffer,
bufferSize,
&decryptedSize);
if (cryptStatus == kCCSuccess) {
result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
} else {
free(buffer);
NSLog(#"[ERROR] failed to decrypt| CCCryptoStatus: %d", cryptStatus);
}
return result;
}
Best guess without any example data, etc is that the key or iv are the incorrect size and/or the padding or mode is different.

Resources