AES/CBC/PKCS5Padding in iOS objective c result differs from Android - ios

I am using the AES/CBC/PKCS5Padding in Android application. Code is like-
private static String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private static String ALGORITHM = "AES";
private static String DIGEST = "MD5";
private static Cipher cipher;
private static SecretKey password;
private static IvParameterSpec IVParamSpec;
private final static String pvtkey="GDNBCGDRFSC$%#%=";
//16-byte private key
private static byte[] IV = pvtkey.getBytes();
public PassWordEncryptor() {
try {
//Encode digest
MessageDigest digest;
digest = MessageDigest.getInstance(DIGEST);
password = new SecretKeySpec(digest.digest(pvtkey.getBytes()), ALGORITHM);
//Initialize objects
cipher = Cipher.getInstance(TRANSFORMATION);
IVParamSpec = new IvParameterSpec(IV);
} catch (NoSuchAlgorithmException e) {
Log.i(Lams4gApp.TAG, "No such algorithm " + ALGORITHM);
} catch (NoSuchPaddingException e) {
System.out.println( "No such padding PKCS7"+ e);
}
}
/**
Encryptor.
#text String to be encrypted
#return Base64 encrypted text
*/
public String encrypt(byte[] text) {
byte[] encryptedData;
try {
cipher.init(Cipher.ENCRYPT_MODE, password, IVParamSpec);
encryptedData = cipher.doFinal(text);
} catch (InvalidKeyException e) {
System.out.println( "Invalid key (invalid encoding, wrong length, uninitialized, etc)."+ e);
return null;
} catch (InvalidAlgorithmParameterException e) {
System.out.println( "Invalid or inappropriate algorithm parameters for " + ALGORITHM+ e);
return null;
} catch (IllegalBlockSizeException e) {
System.out.println( "The length of data provided to a block cipher is incorrect"+ e);
return null;
} catch (BadPaddingException e) {
System.out.println( "The input data but the data is not padded properly."+ e);
return null;
}
return Base64.encodeToString(encryptedData,Base64.DEFAULT);
}
I need similar code in iOS Objective C. Encryption and Decryption results should be same in android and iOS.
Kindly provide the same algorithm for Objective C.
I am using iOS code as-
- (void)viewDidLoad {
[super viewDidLoad];
NSData *encodingData=[self encrypt:[#"slapkh"
dataUsingEncoding:NSUTF8StringEncoding]];
NSString *encodingResult = [NSString base64StringFromData:encodingData length:[encodingData length]];
}
- (NSData *) encrypt:(NSData *) plainText {
return [self transform:kCCEncrypt data:plainText];
}
- (NSData *) decrypt:(NSData *) cipherText {
return [self transform:kCCDecrypt data:cipherText];
}
- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData {
Cipher* cipher = [[Cipher alloc]initWithKey:#"GDNBCGDRFSC$%#%="];
NSString* Key = cipher.cipherKey;
// kCCKeySizeAES128 = 16 bytes
// CC_MD5_DIGEST_LENGTH = 16 bytes
NSData* secretKey = [Cipher md5:Key];
CCCryptorRef cryptor = NULL;
CCCryptorStatus status = kCCSuccess;
uint8_t iv[kCCBlockSizeAES128];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
status = CCCryptorCreate(encryptOrDecrypt,
kCCAlgorithmAES128,kCCOptionPKCS7Padding,
[secretKey bytes], kCCKeySizeAES128, iv, &cryptor);
if (status != kCCSuccess) {
return nil;
}
size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[inputData length],
true);
void * buf = malloc(bufsize * sizeof(uint8_t));
memset(buf, 0x0, bufsize);
size_t bufused = 0;
size_t bytesTotal = 0;
status = CCCryptorUpdate(cryptor, [inputData bytes], (size_t)[inputData length],
buf, bufsize, &bufused);
if (status != kCCSuccess) {
free(buf);
CCCryptorRelease(cryptor);
return nil;
}
bytesTotal += bufused;
status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused);
if (status != kCCSuccess) {
free(buf);
CCCryptorRelease(cryptor);
return nil;
}
bytesTotal += bufused;
CCCryptorRelease(cryptor);
return [NSData dataWithBytesNoCopy:buf length:bytesTotal];
}
But the results for Android and iOS Differs as-
Text to encrypt: slapkh
key: GDNBCGDRFSC$%#%=
Android result: jN2p1yAdBJLRmoHq+k9KtA==\n
iOS Resut: tbaSJFv5mGyZ9t/+kOw+gg==

After spending time dealing with this, I got success in ANDROID(java) and IOS (Objc) using AES with the codes below:
ANDROID CODE
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class SecurityUtils {
private static final String ALGORITHM = "AES";
private static final String MODE = "AES";
private static final String IV = "AEE0715D0778A4E4";
private static final String KEY= "9336365521W5F092BB5909E8E033BC69";
public static String encrypt(String value ) throws NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException {
SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(MODE);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(IV.getBytes()));
byte[] values = cipher.doFinal(value.getBytes());
return Base64.encodeBytes(values);
}
public static String decrypt(String value) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException {
byte[] values = Base64.decode(value);
SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(MODE);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(IV.getBytes()));
return new String(cipher.doFinal(values));
}
}
TESTING ANDROID
try {
String encrypted = SecurityUtils.encrypt("My Secret Text");
String decrypted = SecurityUtils.decrypt(encrypted);
Log.e("encrypted", encrypted);
Log.e("decrypted", decrypted);
}catch(Exception ex){
Log.e("AES", ex.getMessage());
}
IOS CODE
Header file
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCryptor.h>
NS_ASSUME_NONNULL_BEGIN
#interface SecurityUtils : NSObject
+ (NSString *)encrypt:(NSString *)plainText error:(NSError **)error;
+ (NSString *)decrypt:(NSString *)plainText error:(NSError **)error;
#end
NS_ASSUME_NONNULL_END
Implementation file
NSString *const IV = #"AEE0515D0B08A4E4";
NSString *const KEY = #"9336565521E5F082BB5929E8E033BC69";
#import "SecurityUtils.h"
#implementation SecurityUtils
+ (NSString *)encrypt:(NSString *)plainText error:(NSError **)error {
NSMutableData *result = [SecurityUtils doAES:[plainText dataUsingEncoding:NSUTF8StringEncoding] context: kCCEncrypt error:error];
return [result base64EncodedStringWithOptions:0];
}
+ (NSString *)decrypt:(NSString *)encryptedBase64String error:(NSError **)error {
NSData *dataToDecrypt = [[NSData alloc] initWithBase64EncodedString:encryptedBase64String options:0];
NSMutableData *result = [SecurityUtils doAES:dataToDecrypt context: kCCDecrypt error:error];
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
+ (NSMutableData *)doAES:(NSData *)dataIn context:(CCOperation)kCCEncrypt_or_kCCDecrypt error:(NSError **)error {
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0;
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeBlowfish];
NSData *key =[KEY dataUsingEncoding:NSUTF8StringEncoding];
NSData *iv = [IV dataUsingEncoding:NSUTF8StringEncoding];
ccStatus = CCCrypt( kCCEncrypt_or_kCCDecrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
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;
}
#end
IOS TESTING
NSError *error;
NSString *encrypted = [SecurityUtils encrypt:#"My Secret Text" error:&error];
NSLog(#"encrypted: %#",encrypted);
NSLog(#"decrypted: %#",[SecurityUtils decrypt:encrypted error:&error]);
Finally, the outputs of the test:
ANDROID OUTPUT
2019-05-16 21:35:01.215 4920-4920/br.com.my.app E/encrypted: EJ41am5W1k6fA7ygFjTSEw==
2019-05-16 21:35:01.215 4920-4920/br.com.my.app E/decrypted: My Secret Text
IOS OUTPUT
2019-05-16 21:38:02.947043-0300 MyApp[63392:1590665] encrypted: EJ41am5W1k6fA7ygFjTSEw==
2019-05-16 21:38:02.947270-0300 MyApp[63392:1590665] decrypted: My Secret Text
My repo on GitHub with this example.

Related

Objective C - Encryption with AES256 GCM

Currently I'm using the below method for Encryption
+ (NSData*) encrypt:(NSData*)plainText key:(NSData*)key iv:(NSData*)iv {
NSUInteger dataLength = [plainText length];
size_t buffSize = dataLength + kCCBlockSizeAES128;
void *buff = malloc(buffSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus status = CCCrypt(kCCEncrypt, /* kCCEncrypt, etc. */
kCCAlgorithmAES128, /* kCCAlgorithmAES128, etc. */
kCCOptionPKCS7Padding, /* kCCOptionPKCS7Padding, etc. */
key.bytes, kCCKeySizeAES256, /* key and its length */
iv.bytes, /* initialization vector - use random IV everytime */
[plainText bytes], [plainText length], /* input */
buff, buffSize,/* data RETURNED */
&numBytesEncrypted);
if (status == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buff length:numBytesEncrypted];
} else {
// Encryption Failed
}
free(buff);
return nil;
}
I need to use now AES256 GCM for encrypting, I don't see kCCAlgorithmAES256 in CCCrypt. Someone please guide me, I'm using the framework pod 'RNCryptor-objc'.
Below is the decrypt logic handled in backend.
public static byte[] decrypt(byte[] key, byte[] data) {
// TODO utilize GCMAES#decrypt method
try {
if (data.length < NONCE_LENGTH + TAG_LENGTH) {
throw new IllegalArgumentException("data packet too short");
}
int cipherTextLength = data.length - NONCE_LENGTH - TAG_LENGTH;
byte[] nonce = Arrays.copyOf(data, NONCE_LENGTH);
GCMBlockCipher cipher = new GCMBlockCipher(new AESFastEngine());
AEADParameters parameters = new AEADParameters(new KeyParameter(key), TAG_LENGTH * 8, nonce);
cipher.init(false, parameters);
byte[] out = new byte[cipher.getOutputSize(cipherTextLength + TAG_LENGTH)];
int pos = cipher.processBytes(data, NONCE_LENGTH, data.length - NONCE_LENGTH, out, 0);
pos += cipher.doFinal(out, pos);
return Arrays.copyOf(out, pos);
} catch (IllegalStateException | InvalidCipherTextException ex) {
throw new IllegalArgumentException(ex);
}}}

AES Decryption in objective c where encryption in .net

Hello friends I stuck in decryption of data. Server side data is encrypted by .net, i tried many codes but unable to decrypt.
In android data is decrypted by this function
public static String doDecrypt(String data, String key){
String decryptedData = null;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-8");
int len = b.length;
if (len > keyBytes.length)
len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] results = new byte[data.length()];
try {
results = cipher.doFinal(Base64.decode(data,Base64.DEFAULT));
} catch (Exception e) {
Log.i("Erron in Decryption", e.toString());
}
Log.i("Data", new String(results, "UTF-8"));
decryptedData = new String(results, "UTF-8");
}
catch (Exception e) {
e.printStackTrace();
return null;
}
return decryptedData;
}
its working fine in android, but while decrypting in objective c its gives only null.
I used some link that are below:-
nsdata , fwencryption , RNCryptor
But it only gives null value when decrypting in NSString.
For example you can check a demo for decryption
data:-1YbDEEZGnc5EtZY040AaSP233AXZHJVAZb74sCQHm+BX72N5nM81ygDsRHhF8KMk
key- test#123456789
I used this code in Objective c
#import "ViewController.h"
#import "NSData+AES.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *testData = [self decode:#"1YbDEEZGnc5EtZY040AaSP233AXZHJVAZb74sCQHm+BX72N5nM81ygDsRHhF8KMk"];
NSLog(#"Dtata%#",testData);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSString*)encode:(NSString*)plainString {
//convert 'plainString' to NSData using NSUTF8StringEncoding
NSData *plainData = [plainString dataUsingEncoding:NSUTF8StringEncoding];
//encrypt data with AES encryption
NSData *AESData = [plainData AES128EncryptedDataWithKey:#"test#123456789"];
//return base64 encoded string
return [AESData base64EncodedStringWithOptions:0];
}
-(NSString*)decode:(NSString*)encodedString {
//convert 'encodedString' to base64 decoded data
NSData *base64Data = [[NSData alloc] initWithBase64EncodedString:encodedString options:0];
//decode using AES encryption
NSData *AESData = [base64Data AES128DecryptedDataWithKey:#"test#123456789"];
//return string from AES decoded data
return [[NSString alloc] initWithData:AESData encoding:NSUTF8StringEncoding];
}
Please anyone can help me out. I am stuck in this.Thanks in advance.

AES Encryption not the same result iOS and Android

I've been struggling for many days now finding out how to achieve a same result when encrypting plaintext password using AES.
I have codes below in Java (Android) and Objective-C (iOS). Honestly, the ideal result is the one produced by Java because our existing passwords are encrypted with this implementation.
Hopefully someone can pin-point my error for Objective-C. I am a super newbie on this programming language, so please bear with and don't be so hard on me. :)
Many thanks!
The plain text password is:
12345abc
The Java code:
Encrypted text result is:
BS/WyqmZ6AD68YbmFERn9w==
private static String encryptionKey="ERVwiiYMFlDcZ0wp";
private static String decryptionKey="ERVwiiYMFlDcZ0wp";
JSONObject resultJSON=new JSONObject();
private static byte[] initializationVector = new byte[] { 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10 };
public JSONObject encryptMethod(JSONObject jObject)
{
try {
textToEncrypt = jObject.getString("text");
textToEncrypt = replaceSlashes(textToEncrypt);
Log.d("STATE", "textToEncrypt: "+textToEncrypt);
try {
cipherText = encryptData(textToEncrypt);
Log.d("STATE", "cipherText: "+cipherText);
resultType=true;
resultData=cipherText;
resultMessage="Encryption success";
}
catch(Exception e)
{
e.printStackTrace();
resultMessage="Encryption is Not Possible, Please try some other text";
}
}
catch(Exception e)
{
e.printStackTrace();
resultMessage="Wrong Text Input, Please try again";
}
try {
resultJSON.put("type", resultType);
resultJSON.put("message", resultMessage);
resultJSON.put("data", resultData);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return resultJSON;
}
public static String encryptData(String plainText) {
String cipherText = null;
byte[] encryptedBytes = null;
String skeySpecString = null;
if (plainText == null || "".equals(plainText)) {
return null;
}
try {
if(encryptionKey==null || encryptionKey.equals("")) {
return null;
}
SecretKeySpec skeySpec = new SecretKeySpec(encryptionKey.getBytes(), "AES");
IvParameterSpec ivps = new IvParameterSpec(initializationVector);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivps);
encryptedBytes = cipher.doFinal(plainText.getBytes());
encryptedBytes = Base64.encode(encryptedBytes, 0);
cipherText = new String(encryptedBytes);
} catch (BadPaddingException bpe) {
Log.e("Plain", "<===== BadPaddingException =====>", bpe);
return null;
} catch (IllegalBlockSizeException ibse) {
Log.e("Plain", "<===== BadPaddingException =====>", ibse);
return null;
} catch (InvalidAlgorithmParameterException iape) {
Log.e("Plain", "<===== InvalidAlgorithmParameterException =====>",
iape);
return null;
} catch (InvalidKeyException ike) {
Log.e("Plain", "<===== InvalidKeyException =====>", ike);
return null;
} catch (NoSuchAlgorithmException nae) {
Log.e("Plain", "<===== NoSuchAlgorithmException =====>", nae);
return null;
} catch (NoSuchPaddingException nspe) {
Log.e("Plain", "<===== NoSuchPaddingException =====>", nspe);
return null;
} catch (Exception ex) {
Log.e("Plain", "<===== Exception: {0} =====>", ex);
return null;
}
return cipherText;
}
The Objective-C code:
Encrypted text result is:
V+RZjcXVE+J1aG9kwt7CTA==
Encrypt.m file
-(NSString *) encryptData:(NSString *)plainText
{
NSString *passphrase = #"ERVwiiYMFlDcZ0wp";
NSData *key=[passphrase dataUsingEncoding:NSUTF8StringEncoding];
NSData *password = [plainText dataUsingEncoding:NSUTF8StringEncoding];
StringEncryption *crypt = [[StringEncryption alloc] init];
NSData *encryptedData = [crypt AES256EncryptWithKey:passphrase password:plainText];
NSString *ciphertext =[encryptedData base64EncodingWithLineLength:0];
return ciphertext;
}
Crypt.m file
- (NSData *)AES256EncryptWithKey:(NSString *)key password:(NSString *)plainText {
char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [plainText length];
NSData *myData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
const char myByteArray[] = {
0x01,0x02,0x03,0x04,
0x05,0x06,0x07,0x08,
0x09,0x0a,0x0b,0x0c,
0x0d,0x0e,0x0f,0x10 };
NSData *vector = [NSData dataWithBytes: myByteArray length:16];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128,
(__bridge const void *)(vector),
myData.bytes, dataLength,
buffer, bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer);
return nil;
}

DES encrypted value mismatching android and ios

IOS code is
#import "DESCodec.h"
#import <CommonCrypto/CommonCryptor.h>
#implementation DESCodec
{
NSString *key;
}
-(id) init{
self=[super init];
if(self){
key=#"12345678";
}
return self;
}
-(NSString *) decode:(NSString *)encoded{
NSData *inputData = [[NSData alloc] initWithBase64EncodedString:encoded options:0];
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
size_t outLength;
NSMutableData *outputData = [NSMutableData dataWithLength:(inputData.length +
kCCBlockSizeDES)];
CCCryptorStatus
result = CCCrypt(kCCDecrypt, // operation
kCCAlgorithmDES, // Algorithm
kCCOptionPKCS7Padding , // options
keyData.bytes, // key
keyData.length, // keylength
nil,// iv
inputData.bytes, // dataIn
inputData.length, // dataInLength,
outputData.mutableBytes, // dataOut
outputData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result != kCCSuccess) {
return nil;
}
[outputData setLength:outLength];
return [[NSString alloc] initWithData:outputData `encoding:NSUTF8StringEncoding];`
}
-(NSString *) encode:(NSString *)decoded{
NSData *inputData = [decoded dataUsingEncoding:NSUTF8StringEncoding];
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
size_t outLength;
NSMutableData *outputData = [NSMutableData dataWithLength:(inputData.length + kCCBlockSizeDES)];
CCCryptorStatus result = CCCrypt(kCCEncrypt, // operation
kCCAlgorithmDES, // Algorithm
kCCOptionPKCS7Padding, // options
keyData.bytes, // key
keyData.length, // keylength
nil,// iv
inputData.bytes, // dataIn
inputData.length, // dataInLength,
outputData.mutableBytes, // dataOut
outputData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result != kCCSuccess) {
return nil;
}
[outputData setLength:outLength];
NSString *r = [outputData base64EncodedStringWithOptions:0];
return r;
}
#end
DESCodec *codec=[[DESCodec alloc] init];
NSString *encoded=[codec encode:#"12345678"];
NSString decoded=[codec decode:encoded];
NSLog(#" %# %#",encoded,decoded);
value is ltACiHjVjImOJQ1fTHZkSw== and 12345678
but in java encypted text is "ltACiHjVjIn+uVm31GQvyw=="
I not good in Objective C and I can't able to trigger out the problem.
can anybody please help me. Thanks and regards
Java code is
public class DESCodec {
/**
* Secret key that shall be used for encryption and decryption.
*/
private String strSecretKey = "12345678";
private static final String UNICODE_FORMAT = "UTF-8";
private static final String DES_ENCRYPTION_SCHEME = "DES";
private static final String TAG = "DESCodec";
private Cipher cipher;
private SecretKey key;
public DESCodec() {
try {
this.strSecretKey = strSecretKey;
String myEncryptionScheme = DES_ENCRYPTION_SCHEME;
byte[] keyAsBytes = strSecretKey.getBytes(UNICODE_FORMAT);
DESKeySpec myKeySpec = new DESKeySpec(keyAsBytes);
SecretKeyFactory mySecretKeyFactory = SecretKeyFactory.getInstance(myEncryptionScheme);
cipher = Cipher.getInstance(myEncryptionScheme);
key = mySecretKeyFactory.generateSecret(myKeySpec);
} catch (Exception e) {
e.printStackTrace();
}
}
public String desEncrypt(String message) {
String encryptedString = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainText = message.getBytes(UNICODE_FORMAT);
byte[] encryptedText = cipher.doFinal(plainText);
encryptedString = Base64.encodeToString(encryptedText, Base64.DEFAULT);
} catch (Exception e) {
e.printStackTrace();
}
return encryptedString;
}
public String desDecrypt(String message) {
String decryptedText = null;
try {
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] encryptedText = Base64.decode(message, Base64.DEFAULT);
byte[] plainText = cipher.doFinal(encryptedText);
decryptedText = bytes2String(plainText);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedText;
}
private String bytes2String(byte[] bytes) {
try {
return new String(bytes, UNICODE_FORMAT);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}
It's obviously only a problem with the mode of operation, because the first block matches. In Java you're using ECB mode, because "DES" defaults to "DES/ECB/PKCS5Padding". I think that CCCryptor defaults to CBC.
Don't ever use ECB mode. It's not semantically secure. You need to use at least CBC mode with a random IV. The IV doesn't have to be secret, so you can prepend it to the ciphertext. Please look at RNCryptor that has additional security features like authentication of ciphertext. It also has a Java implementation.
Don't use DES anymore. It's not secure anymore. You should use AES. Triple DES is also not that bad.
I hava the same problem when i develop an iOS app.And the android client is used by many people, so i couldn't change the algorithm to AES or others.As Artjom B. said in Java 'DES' defaults to 'DES/ECB/PKCS5Padding', in the source you can find that
Cipher c1 = Cipher.getInstance("DES/ECB/PKCS5Padding");
but unfortunately in iOS you just find that
enum {
kCCOptionPKCS7Padding = 0x0001,
kCCOptionECBMode = 0x0002
}
But finally i find a solution like this
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding | kCCOptionECBMode,
[key UTF8String],
kCCKeySizeDES,
nil,
[cipherData bytes],
[cipherData length],
buffer,
1024,
&numBytesDecrypted);
The importance is kCCOptionPKCS7Padding | kCCOptionECBMode, you can try this method.

Issue with digital signature generated using Podofo library

I'm using OpenSSL to generate digital signature for a PDF by PoDoFo library.
Here is the logic for signature handler
OpenSSLSignatureHandler.h
#import <Foundation/Foundation.h>
// OpenSSL includes
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pkcs12.h>
#include <openssl/pkcs7.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#interface OpenSSLSignatureHandler : NSObject
{
SHA_CTX m_sha_ctx;
EVP_PKEY* mp_pkey; // private key
X509* mp_x509; // signing certificate
STACK_OF(X509)* mp_ca; // certificate chain up to the CA
}
- (id) initWithCert:(NSString*) p12file password: (NSString*) password;
- (void) AppendData: (NSData*)data;
- (NSData*) getSignature;
#end
OpenSSLSignatureHandler.m
#import "OpenSSLSignatureHandler.h"
#include <string>
#implementation OpenSSLSignatureHandler
- (id) initWithCert:(NSString*) p12file password: (NSString*) password{
if (self = [super init]) {
// Initialize OpenSSL library
CRYPTO_malloc_init();
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
FILE* fp = fopen([p12file cStringUsingEncoding: NSASCIIStringEncoding], "rb");
if (fp == NULL)
#throw ([NSException exceptionWithName: #"PDFNet Exception" reason: #"Cannot open private key." userInfo: nil]);
PKCS12* p12 = d2i_PKCS12_fp(fp, NULL);
fclose(fp);
if (p12 == NULL)
#throw ([NSException exceptionWithName: #"PDFNet Exception" reason: #"Cannot parse private key." userInfo: nil]);
mp_pkey = NULL;
mp_x509 = NULL;
mp_ca = NULL;
int parseResult = PKCS12_parse(p12, [password cStringUsingEncoding: NSASCIIStringEncoding], &mp_pkey, &mp_x509, &mp_ca);
PKCS12_free(p12);
if (parseResult == 0)
#throw ([NSException exceptionWithName: #"PDFNet Exception" reason: #"Cannot parse private key." userInfo: nil]);
//initialize sha context
SHA1_Init(&m_sha_ctx);
}
return self;
}
- (void) AppendData: (NSData*)data
{
SHA1_Update(&m_sha_ctx, [data bytes], [data length]);
return;
}
- (BOOL) Reset
{
SHA1_Init(&m_sha_ctx);
return (YES);
}
- (NSData*) getSignature
{
unsigned char sha_buffer[SHA_DIGEST_LENGTH];
memset((void*) sha_buffer, 0, SHA_DIGEST_LENGTH);
SHA1_Final(sha_buffer, &m_sha_ctx);
PKCS7* p7 = PKCS7_new();
PKCS7_set_type(p7, NID_pkcs7_signed);
PKCS7_SIGNER_INFO* p7Si = PKCS7_add_signature(p7, mp_x509, mp_pkey, EVP_sha1());
PKCS7_add_attrib_content_type(p7Si, OBJ_nid2obj(NID_pkcs7_data));
PKCS7_add0_attrib_signing_time(p7Si, NULL);
PKCS7_add1_attrib_digest(p7Si, (const unsigned char*) sha_buffer, SHA_DIGEST_LENGTH);
PKCS7_add_certificate(p7, mp_x509);
int c = 0;
for ( ; c < sk_X509_num(mp_ca); c++) {
X509* cert = sk_X509_value(mp_ca, c);
PKCS7_add_certificate(p7, cert);
}
PKCS7_set_detached(p7, 1);
PKCS7_content_new(p7, NID_pkcs7_data);
PKCS7_SIGNER_INFO_sign(p7Si);
int p7Len = i2d_PKCS7(p7, NULL);
NSMutableData* signature = [NSMutableData data];
unsigned char* p7Buf = (unsigned char*) malloc(p7Len);
if (p7Buf != NULL) {
unsigned char* pP7Buf = p7Buf;
i2d_PKCS7(p7, &pP7Buf);
[signature appendBytes: (const void*) p7Buf length: p7Len];
free(p7Buf);
}
PKCS7_free(p7);
return (signature);
}
- (void) dealloc
{
sk_X509_free(mp_ca);
X509_free(mp_x509);
EVP_PKEY_free(mp_pkey);
// Release OpenSSL resource usage
ERR_free_strings();
EVP_cleanup();
[super dealloc];
}
#end
Using podofo to embed signature
void CreateSimpleForm( PoDoFo::PdfPage* pPage, PoDoFo::PdfStreamedDocument* pDoc, const PoDoFo::PdfData &signatureData )
{
PoDoFo::PdfPainter painter;
PoDoFo::PdfFont* pFont = pDoc->CreateFont( "Courier" );
painter.SetPage( pPage );
painter.SetFont( pFont );
painter.DrawText( 10000 * CONVERSION_CONSTANT, 280000 * CONVERSION_CONSTANT, "PoDoFo Sign Test" );
painter.FinishPage();
PoDoFo::PdfSignatureField signField( pPage, PoDoFo::PdfRect( 0, 0, 0, 0 ), pDoc );
signField.SetFieldName("SignatureFieldName");
signField.SetSignature(signatureData);
signField.SetSignatureReason("Document verification");
// Set time of signing
signField.SetSignatureDate( PoDoFo::PdfDate() );
}
+(void)addDigitalSignatureOnPage:(NSInteger)pageIndex outpath:(NSString*)path/*doc:(PoDoFo::PdfMemDocument*)aDoc*/{
PoDoFo::PdfPage* pPage;
PoDoFo::PdfSignOutputDevice signer([path UTF8String]);
// Reserve space for signature
signer.SetSignatureSize(1024);
if([[NSFileManager defaultManager] fileExistsAtPath:path]){
PoDoFo::PdfStreamedDocument writer( &signer, PoDoFo::ePdfVersion_1_5 );
// Disable default appearance
writer.GetAcroForm(PoDoFo::ePdfCreateObject, PoDoFo::PdfAcroForm::ePdfAcroFormDefaultAppearance_None);
pPage = writer.CreatePage(PoDoFo::PdfPage::CreateStandardPageSize(PoDoFo::ePdfPageSize_A4 ) );
TEST_SAFE_OP( CreateSimpleForm( pPage, &writer, *signer.GetSignatureBeacon() ) );
TEST_SAFE_OP( writer.Close() );
}
// Check if position of signature was found
if(signer.HasSignaturePosition()) {
// Adjust ByteRange for signature
signer.AdjustByteRange();
// Read data for signature and count it
// We have to seek at the beginning of the file
signer.Seek(0);
//OpenSSLSignatureHandler
NSString * p12certpath = [[NSBundle mainBundle] pathForResource:#"iphone-cert" ofType:#"p12"];
OpenSSLSignatureHandler*signatureHandler = [[OpenSSLSignatureHandler alloc] initWithCert:p12certpath password:#"test123$"];
char buff[65536];
size_t len;
while( (len = signer.ReadForSignature(buff, 65536))>0 )
{
NSData* data = [NSData dataWithBytes:(const void *)buff length:len];
[signatureHandler AppendData:data];
}
const PoDoFo::PdfData *pSignature = NULL;
// NSString *pkcsMessage = [[signatureHandler getSignature] base64EncodedString];
// NSLog(#"OpenSSLSignatureHandler signature message = %#",pkcsMessage);
// const char * cstr = [pkcsMessage UTF8String];
// if(pSignature==NULL)pSignature = new PoDoFo::PdfData(cstr, sizeof(cstr));
unsigned char *bytePtr = (unsigned char *)[[signatureHandler getSignature] bytes];
std::string str;
str.append(reinterpret_cast<const char*>(bytePtr));
// Paste signature to the file
if(pSignature==NULL)pSignature = new PoDoFo::PdfData(str.c_str(), sizeof(str));
NSLog(#"str = %s",str.c_str());
NSLog(#"sizeof(str) = %lu",sizeof(str));
signer.SetSignature(*pSignature);
}
signer.Flush();
}
But the signature that's embeded in the PDF is always empty
can some help with this issue ?

Resources