I'm trying to code a crypto java testclass which encrypt and decrypt a String password with BouncyCastle. The main() is very simple, I do encryptPass() and then decryptPass(), and I watch the console trace.
The problem is when it tries to decrypt, I got a padding exception :
javax.crypto.BadPaddingException: pad block corrupted
at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at com.kiengi.crypto.Crypto.decryptPass(Crypto.java:79)
My code is the following for the Crypto class :
// password to be crypted
public String pass = "password_go_here";
// key for encrypt pass
public String passKey = generateRandomKey(); // generation clef 16 caractere [a-zA-Z0-9]
// Encrypted pass
public String cryptedPass;
public final Logger logger = Logger.getLogger(this.getClass());
private final static byte[] IV_BYTES = new byte[] { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
0x00, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
public Crypto() {
super();
}
public void encryptPass(){
Security.addProvider(new BouncyCastleProvider());
IvParameterSpec _ivSpec = new IvParameterSpec(IV_BYTES);
try{
KeyGenerator _keygen = KeyGenerator.getInstance("AES");
_keygen.init(new SecureRandom(passKey.getBytes()));
SecretKey _key = _keygen.generateKey();
logger.trace("Secret key generated");
Cipher _cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
_cipher.init(Cipher.ENCRYPT_MODE, _key, _ivSpec);
cryptedPass = asHex(_cipher.doFinal(pass.getBytes("UTF-8")));
logger.trace("Encrypted pass : "+cryptedPass);
}catch (Exception e) {
logger.warn("encrypt failed");
e.printStackTrace();
}
}
public void decryptPass() {
byte[] _passKey = passKey.getBytes();
byte[] _cryptedPass = hexFromString(cryptedPass);
Security.addProvider(new BouncyCastleProvider());
IvParameterSpec _ivSpec = new IvParameterSpec(IV_BYTES);
try {
KeyGenerator _keygen = KeyGenerator.getInstance("AES");
_keygen.init(new SecureRandom(_passKey));
SecretKey _key = _keygen.generateKey();
logger.trace("Secret key generated");
Cipher _cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
_cipher.init(Cipher.DECRYPT_MODE, _key, _ivSpec);
String _pass = new String(_cipher.doFinal(_cryptedPass), "UTF-8");
logger.trace("Decrypted pass : "+_pass);
} catch (Exception e) {
logger.warn("decrypt failed");
e.printStackTrace();
}
}
private int fromDigit(char ch) {
if ((ch >= '0') && (ch <= '9')) {
return ch - '0';
} else if ((ch >= 'A') && (ch <= 'F')) {
return ch + 10 - 'A';
} else if ((ch >= 'a') && (ch <= 'f')) {
return ch + 10 - 'a';
} else {
throw new IllegalArgumentException(String.format(
"Invalid hex character 0x%04x", 0xff & ch));
}
}
private byte[] hexFromString(String hex) {
final byte[] buf = new byte[hex.length() / 2];
for (int i = 0, j = 0; i < hex.length(); i += 2) {
buf[j++] = (byte) (fromDigit(hex.charAt(i)) << 4 | fromDigit(hex
.charAt(i + 1)));
}
return buf;
}
private static String asHex(byte buf[]) {
final Formatter formatter = new Formatter(new StringBuffer());
for (int i = 0; i < buf.length; i++) {
formatter.format("%02x", 0xff & buf[i]);
}
return formatter.toString();
}
private String generateRandomKey() {
String _chars = "abcdefABCDEF1234567890";
StringBuffer _pass = new StringBuffer();
for (int x = 0; x < 32; x++) {
int i = (int) Math.floor(Math.random() * (_chars.length() - 1));
_pass.append(_chars.charAt(i));
}
return _pass.toString();
}
Does anyone knows what this exception means?
This code has a bug. It assumes that new SecureRandom(passKey.getBytes()) will initialize the SecureRandom instance with only the bytes supplied in the constructor. This is wrong. The data in the constructor will supplement whatever entropy sources SecureRandom uses, not replace them.
You need to use a proper password-based encryption (PBE) scheme.
This exception means that padding block is corrupted. You use PKCS#7 padding with 16B blocks. In this sample your output is 16B too. So it always should be added block with 16 bytes of value 0x10.
The padding is corrupted because the decryption is corrupted. Your SecureRandom implementation adds its own entropy and generates wrong decryption key. This SecureRandom constructor uses the first PRNG algorithm of the first provider that has registered a SecureRandom implementation.
Related
In Java code, i have source work well, this is use for encrypt:
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class HelloWorld{
private static final String hexKey = "B8EE12E123C0E300A202074A153CC0D27D739357480FFFFFFFFFFFFFFFFFFFEF";
public static void main(String []args){
System.out.println("Encryt ==== ");
String textToEncrypt = "From=ABC&Key=FootID1234&Value=ResultValue2324";
String encryptedText = encrypt(textToEncrypt);
System.out.println(encryptedText);
System.out.println("Decrypt ==== ");
String decryptedText = decrypt(encryptedText);
System.out.println(decryptedText);
}
public static String encrypt (String plainText) {
String encryptedText = null;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecretKeySpec secretKey = new SecretKeySpec(hexToBytes(hexKey), "AES");
IvParameterSpec ivparameterspec = new IvParameterSpec(hexKey.getBytes(), 0, 16);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivparameterspec);
byte[] cipherText = cipher.doFinal(plainText.getBytes("UTF8"));
encryptedText = bytesToHex(cipherText);
} catch (Exception E) {
System.out.println("Encrypt Exception : " + E.getMessage());
}
return encryptedText;
}
public static String decrypt(String encryptedText) {
String decryptedText = null;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecretKeySpec secretKey = new SecretKeySpec(hexToBytes(hexKey), "AES");
IvParameterSpec ivparameterspec = new IvParameterSpec(hexKey.getBytes("UTF8"), 0, 16);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivparameterspec);
byte[] cipherText = hexToBytes(encryptedText);
byte[] dcrbyte = cipher.doFinal(cipherText);
decryptedText = new String(dcrbyte, "UTF-8");
} catch (Exception E) {
System.out.println("Encrypt Exception : " + E.getMessage());
}
return decryptedText;
}
private static byte[] hexToBytes(String hexStr) {
byte[] val = new byte[hexStr.length() / 2];
for (int i = 0; i < val.length; i++) {
int idx = i * 2;
int j = Integer.parseInt(hexStr.substring(idx, idx + 2), 16);
val[i] = (byte) j;
}
return val;
}
private static String bytesToHex(byte[] hashInBytes) {
char[] hexArray = "0123456789ABCDEF".toCharArray();
char[] hexChars = new char[hashInBytes.length * 2];
for (int i = 0; i < hashInBytes.length; i++) {
int v = hashInBytes[i] & 0xFF;
hexChars[i * 2] = hexArray[v >>> 4];
hexChars[i * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}
And in c#, i try to write decryptAes() function like this:
public static class Encryption
{
// use these parameters to test decryptAes()
//string key = "B8EE12E123C0E300A202074A153CC0D27D739357480FFFFFFFFFFFFFFFFFFFEF";
//string textToDecrypt = "756AD4D80E2CF1E289D55A23E092F012E8D5F372A343A419BC87F77B6335F04EFB41C3B56F5CDA167F90F67CD672A186";
public static string decryptAes(string key, string textToDecrypt)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
// Assumed Mode and padding values.
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
// AssumedKeySize and BlockSize values.
rijndaelCipher.KeySize = 0x80; //128
rijndaelCipher.BlockSize = 0x80;
// Convert Hex keys to byte Array.
byte[] encryptedData = HexToBytes(textToDecrypt);
//byte[] pwdBytes = System.Text.Encoding.GetEncoding("UTF-8").GetBytes(key);
byte[] pwdBytes = HexToBytes(key);
byte[] keyBytes = new byte[0x10]; //16
int len = pwdBytes.Length;
if (len > keyBytes.Length)
{
len = keyBytes.Length;
}
Array.Copy(pwdBytes, keyBytes, len);
rijndaelCipher.Key = keyBytes;
rijndaelCipher.IV = keyBytes;
// Decrypt data
byte[] plainText = rijndaelCipher.CreateDecryptor()
.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
return Encoding.UTF8.GetString(plainText);
}
public static byte[] HexToBytes(string str)
{
if (str.Length == 0 || str.Length % 2 != 0)
return new byte[0];
byte[] buffer = new byte[str.Length / 2];
char c;
for (int bx = 0, sx = 0; bx < buffer.Length; ++bx, ++sx)
{
// Convert first half of byte
c = str[sx];
buffer[bx] = (byte)((c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0')) << 4);
// Convert second half of byte
c = str[++sx];
buffer[bx] |= (byte)(c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0'));
}
return buffer;
}
public static string ByteToHex(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString().ToUpper();
}
}
But the c# decryptAes() function does not work as i expect. An error
System.Security.Cryptography.CryptographicException: 'Padding is invalid and cannot be removed.'
has occured at line rijndaelCipher.Padding = PaddingMode.PKCS7;
When i change to rijndaelCipher.Padding = PaddingMode.None, it does not work as i expect, the c# result is not the same as the result of java.
Please help, any advice would be appreciated!
Thanks!
You need to explicitly set the padding for both encryption and decryption. Unless you have a reason to do otherwise, use PKCS#7 padding.
rijndaelCipher.Padding=PaddingMode.none;
I have to encrypt a string in my iPhone app. The encryption scheme is 3DES/CBC/PKCS5 padding and I have to convert in objective-c this Java code:
public class MessageEncrypt {
public String encryptString(String message, String seckey) throws Exception{
byte[] encData = encrypt(message, seckey);
return this.getHexString(encData, "");
}
public String decryptString(String message, String seckey) throws Exception{
return decrypt(this.getBArray(message), seckey);
}
private byte[] encrypt(String message, String seckey) throws Exception {
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest(seckey.getBytes("utf-8"));
final byte[] keyBytes = acopyof(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
final byte[] plainTextBytes = message.getBytes("utf-8");
final byte[] cipherText = cipher.doFinal(plainTextBytes);
// final String encodedCipherText = new sun.misc.BASE64Encoder()
// .encode(cipherText);
return cipherText;
}
private String decrypt(byte[] message, String seckey) throws Exception {
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest(seckey.getBytes("utf-8"));
final byte[] keyBytes = acopyof(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
decipher.init(Cipher.DECRYPT_MODE, key, iv);
final byte[] plainText = decipher.doFinal(message);
return new String(plainText, "UTF-8");
}
private String getHexString(byte[] barray, String delim) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < barray.length; i++) {
int ii = barray[i] & 0xFF;
String bInt = Integer.toHexString(ii);
if (ii < 16) {
bInt = "0" + bInt.toUpperCase();
}
buffer.append(bInt);
if (i < barray.length - 1) {
buffer.append(delim);
}
}
return buffer.toString().toUpperCase();
}
private byte[] getBArray(String bString) {
byte[] retBytes;
if (bString.length() % 2 != 0) {
return new byte[0];
}
retBytes = new byte[bString.length() / 2];
for (int i = 0; i < bString.length() / 2; i++) {
retBytes[i] = (byte) ((Character.digit(bString.charAt(2 * i), 16) << 4) + Character.digit(bString.charAt(2 * i + 1), 16));
}
return retBytes;
}
public static byte[] acopyof(byte[] orig, int newlength){
byte[] copya = new byte[newlength];
for(int i=0;i< orig.length;i++){
copya[i]=orig[i];
}
for(int i=orig.length;i<newlength;i++){
copya[i]=0x0;
}
return copya;
}
}
I made this objective-c method to match those specs:
+(NSString*)doCipher:(NSString*)sTextIn:(CCOperation)encryptOrDecrypt {
// const void *vplainText;
// size_t plainTextBufferSize;
NSMutableData *dTextIn;
if (encryptOrDecrypt == kCCDecrypt)
{
}
else
{
dTextIn = [[sTextIn dataUsingEncoding: NSASCIIStringEncoding]mutableCopy];
}
NSLog(#"************** Init encrypting **********************************");
NSLog(#"This is data to encrypt %#",dTextIn);
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
// uint8_t ivkCCBlockSize3DES;
bufferPtrSize = ([dTextIn length] + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x00, bufferPtrSize);
// Initialization vector; in this case 8 bytes.
uint8_t iv[kCCBlockSize3DES];
memset((void *) iv, 0x8, (size_t) sizeof(iv));
UserAndPassword *userPass = [[UserAndPassword alloc]init];
NSString *userPassword = userPass.password;
NSLog(#"This is my password %#",userPassword);
NSString *key = [userPassword MD5String];
NSLog(#"This is MD5 key %#",key);
NSMutableData *_keyData = [[key dataUsingEncoding:NSASCIIStringEncoding]mutableCopy];
unsigned char *bytePtr = (unsigned char *)[_keyData bytes];
NSLog(#"Bytes of key are %s ", bytePtr);
NSLog(#"******** This is my key length %d *******",[_keyData length]);
[_keyData setLength:24];
unsigned char *bytePtr1 = (unsigned char *)[_keyData bytes];
NSLog(#"******** Bytes of key are %s ************", bytePtr1);
NSLog(#"********* This is key length %d ***********",[_keyData length]);
ccStatus = CCCrypt(encryptOrDecrypt, // CCoperation op
kCCAlgorithm3DES, // CCAlgorithm alg
kCCOptionPKCS7Padding, // CCOptions
[_keyData bytes], // const void *key
kCCKeySize3DES, // 3DES key size length 24 bit
iv, //const void *iv,
[dTextIn bytes], // const void *dataIn
[dTextIn length], // size_t dataInLength
(void *)bufferPtr, // void *dataOut
bufferPtrSize, // size_t dataOutAvailable
&movedBytes); // size_t *dataOutMoved
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]];
result = [[[NSString alloc] initWithData:[NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes] encoding:NSUTF8StringEncoding] autorelease];
}
else
{
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
NSLog(#"This is my encrypted bytes %#", myData);
result = [NSString dataToHex:myData];
NSLog(#"This is my encrypted string %#", result);
NSLog(#"********************** Encryption is finished ************");
}
return result;
}
I didn't manage to match the 3DES encryption obtained with Java code and I don't understand which is the problem.
Thank you in advance,
Pier
The Java version is using an IV of 0s, while the Objective-C version uses 8s.
Deriving a key from a password using one round of MD5 and no salt is not secure. Use a key derivation algorithm like PBKDF2.
I haven't looked through all your code, but the first thing that jumps out is that the character encoding schemes for your input strings are different. In your Java algorithm you are encoding all strings as UTF-8, but in your ObjC algorithm you encoded the strings as ASCII, which is a potential problem for anything but the simplest of input strings.
It looks like you have a character encoding problem. Your Objective-C code is based on ASCII (8 bit) characters but you need to switch (16 bit) UNICODE character decoding while parsing Java Strings into bytes. On the other hand, It may be a good idea to consider byte ordering in your arrays depending on the CPU architecture you are working on (Little or Big Endianness).
Really a buggy question , hee is the code:
import java.io.IOException;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class Encryption {
public static final int a = 0x9F224;
public static final int b = 0x98C36;
public static final int c = 0x776a2;
public static final int d = 0x87667;
private String preMaster;
IvParameterSpec ivSpec = new IvParameterSpec(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01 });
private byte[] text;
private SecretKey secret;
private byte[] sKey;
protected SecretKey passwordKey;
protected PBEParameterSpec paramSpec;
public static final String ENCYT_ALGORITHM = "AES/CBC/PKCS7Padding";
public static final String KEY_ALGORITHM = "PBEWITHSHA256AND256BITAES-CBC-BC" ;
//BENCYT_ALGORITHMSE64Encoder encod = new BENCYT_ALGORITHMSE64Encoder();
//BENCYT_ALGORITHMSE64Decoder decod = new BENCYT_ALGORITHMSE64Decoder();
public Encryption(String preMaster,String text,int x){
this.preMaster=preMaster;
this.text=Encoder.decode(text.toCharArray());
try {
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(256);
secret = kg.generateKey();
} catch (Exception e) {
// TODO ENCYT_ALGORITHMuto-generated catch block
e.printStackTrace();
}
}
public Encryption(String key,String text){
try {
this.text = Encoder.decode(text.toCharArray());
this.sKey = Encoder.decode(key.toCharArray());
} catch (Exception e) {
e.printStackTrace();
}
}
public String preMaster() {
byte[] keys = null;
keys = preMaster.getBytes();
int x = -1;
int process = 0;
while (x < keys.length - 2) {
x++;
switch (x) {
case 1:
process = keys[x + 1] | a ^ c & (d | keys[x] % a);
case 2:
process += a | (keys[x] ^ c) & d;
case 3:
process += keys[x] ^ (keys[x + 1] / a) % d ^ b;
default:
process += keys[x + 1] / (keys[x] ^ c | d);
}
}
byte[] xs = new byte[] { (byte) (process >>> 24),
(byte) (process >> 16 & 0xff), (byte) (process >> 8 & 0xff),
(byte) (process & 0xff) };
preMaster = new String(xs);
KeyGenerators key = new KeyGenerators(preMaster);
String toMaster = key.calculateSecurityHash("MD5")
+ key.calculateSecurityHash("MD2")
+ key.calculateSecurityHash("SHA-512");
return toMaster;
}
public String keyWrapper(){
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Key SharedKey = secret;
String key = null;
char[] preMaster = this.preMaster().toCharArray();
try {
byte[]salt={ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
paramSpec = new PBEParameterSpec(salt,20);
PBEKeySpec keySpec = new PBEKeySpec(preMaster);
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
passwordKey = factory.generateSecret(keySpec);
Cipher c = Cipher.getInstance(KEY_ALGORITHM);
c.init(Cipher.WRAP_MODE, passwordKey, paramSpec);
byte[] wrappedKey = c.wrap(SharedKey);
key=Encoder.encode(wrappedKey);
}catch(Exception e){
e.printStackTrace();
}
return key;
}
public Key KeyUnwrapper(){
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
byte[] wrappedKey = sKey;
Key unWrapped = null;
try{
Cipher c = Cipher.getInstance(KEY_ALGORITHM,"BC");
c.init(Cipher.UNWRAP_MODE, passwordKey, paramSpec);
unWrapped = c.unwrap(wrappedKey, ENCYT_ALGORITHM, Cipher.SECRET_KEY);
}catch(Exception e){
e.printStackTrace();
}
return unWrapped;
}
public String encrypt(){
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
SecretKey key = secret;
String result=null;
try{
Cipher cipher = Cipher.getInstance(ENCYT_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
result =Encoder.encode(cipher.doFinal(text));
}catch(Exception e){
e.printStackTrace();
}
return result;
}
public String decrypt(){
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
String result = null;
SecretKey key = (SecretKey) KeyUnwrapper();
try{
Cipher cipher = Cipher.getInstance(ENCYT_ALGORITHM, "BC");
cipher.init(Cipher.DECRYPT_MODE, key);
result = Encoder.encode(cipher.doFinal(text));
}catch(Exception e){
e.printStackTrace();
}
return result;
}
public static void main(String[] args) throws IOException{
Encryption en = new Encryption("123456","Hello World",0);
String enText = en.encrypt();
String key = en.keyWrapper();
System.out.println(key);
System.out.println(enText);
Encryption de = new Encryption(key,enText);
String plainText = de.decrypt();
System.out.println(plainText);
}
And , this is the result ... i tried all the combinations i can, but none of them works ..
F63DE3EE8CEECF4DF76836CA6D69A3903BD87B5726656C54C1C8EC30B6653B2C0E5C7672BE3CF4BE7B2DC7AC5D07DEA0
F1C8D92E5F74019C569D54D70045ADD6
java.lang.NullPointerException
at org.bouncycastle.jce.provider.JCEBlockCipher.engineInit(Unknown Source)
at javax.crypto.Cipher.init(DashoA13*..)
at javax.crypto.Cipher.init(DashoA13*..)
at fiador.authentication.util.Encryption.KeyUnwrapper(Encryption.java:114)
at fiador.authentication.util.Encryption.decrypt(Encryption.java:142)
at fiador.authentication.util.Encryption.main(Encryption.java:160)
java.lang.NullPointerException
at org.bouncycastle.jce.provider.JCEBlockCipher.engineInit(Unknown Source)
at javax.crypto.Cipher.a(DashoA13*..)
at javax.crypto.Cipher.a(DashoA13*..)
at javax.crypto.Cipher.init(DashoA13*..)
at javax.crypto.Cipher.init(DashoA13*..)
at fiador.authentication.util.Encryption.decrypt(Encryption.java:145)
at fiador.authentication.util.Encryption.main(Encryption.java:160)
null
The first NullPointerException occurs inside this method call (in the KeyUnwrapper method):
c.init(Cipher.UNWRAP_MODE, passwordKey, paramSpec);
Have a look: Could one of these arguments be null?
Looking at the code, it seems like passwordKey is only assigned to in keyWrapper, but this is not called on this instance of your class.
I am trying to generate a key for encryption:
public static final String ENCYT_ALGORITHM = "AES/ECB/PKCS7Padding";
public static final String KEY_ALGORITHM = "PBEWITHSHA256AND256BITAES-CBC-BC" ;
//BENCYT_ALGORITHMSE64Encoder encod = new BENCYT_ALGORITHMSE64Encoder();
//BENCYT_ALGORITHMSE64Decoder decod = new BENCYT_ALGORITHMSE64Decoder();
public Encryption(String preMaster,String text,int x){
this.preMaster=preMaster;
this.text=text.getBytes();
}
public void keyGenerator(){
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance("AES");
secret = kg.generateKey();
} catch (Exception e) {
// TODO ENCYT_ALGORITHMuto-generated catch block
e.printStackTrace();
}
}
public String preMaster() {
byte[] keys = null;
keys = preMaster.getBytes();
int x = -1;
int process = 0;
while (x < keys.length - 2) {
x++;
switch (x) {
case 1:
process = keys[x + 1] | a ^ c & (d | keys[x] % a);
case 2:
process += a | (keys[x] ^ c) & d;
case 3:
process += keys[x] ^ (keys[x + 1] / a) % d ^ b;
default:
process += keys[x + 1] / (keys[x] ^ c | d);
}
}
byte[] xs = new byte[] { (byte) (process >>> 24),
(byte) (process >> 16 & 0xff), (byte) (process >> 8 & 0xff),
(byte) (process & 0xff) };
preMaster = new String(xs);
KeyGenerators key = new KeyGenerators(preMaster);
String toMaster = key.calculateSecurityHash("MD5")
+ key.calculateSecurityHash("MD2")
+ key.calculateSecurityHash("SHA-512");
return toMaster;
}
public String keyWrapper(){
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Key SharedKey = secret;
String key = null;
char[] preMaster = this.preMaster().toCharArray();
try {
byte[]salt={ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
paramSpec = new PBEParameterSpec(salt,256);
PBEKeySpec keySpec = new PBEKeySpec(preMaster,salt,1024,256);
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
passwordKey = factory.generateSecret(keySpec);
Cipher c = Cipher.getInstance(KEY_ALGORITHM);
c.init(Cipher.WRAP_MODE, passwordKey, paramSpec);
byte[] wrappedKey = c.wrap(SharedKey);
key=new String(wrappedKey,"UTF8");
}catch(Exception e){
e.printStackTrace();
}
return key;
}
And this is the result :
java.security.InvalidKeyException: Illegal key size
at javax.crypto.Cipher.a(DashoA13*..)
at javax.crypto.Cipher.a(DashoA13*..)
at javax.crypto.Cipher.a(DashoA13*..)
at javax.crypto.Cipher.init(DashoA13*..)
at javax.crypto.Cipher.init(DashoA13*..)
at fiador.authentication.util.Encryption.keyWrapper(Encryption.java:101)
at fiador.authentication.util.Encryption.main(Encryption.java:144)
null
I am really desperate ... please help me, thanks !
You have not installed the unlimited strength crypto files, (the default JDK install allows 128 bit keys as documented in http://download.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppC).
Download unlimited strength crypto package here.
Installation Help
I can't see where keyGenerator is being called. If it is not called, then secret is not being initialized. That could be the cause of the root exception. (It is hard to tell, because you've left out the declaration of secret.)
I'm trying to encrypt data between my android application and a PHP webservice.
I found the next piece of code in this website: http://schneimi.wordpress.com/2008/11/25/aes-128bit-encryption-between-java-and-php/
But when I try to decrypt I get the Exception of the title "data not block size aligned"
This are the method in my MCrypt class
public String encrypt(String text) throws Exception
{
if(text == null || text.length() == 0)
throw new Exception("Empty string");
Cipher cipher;
byte[] encrypted = null;
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
encrypted = cipher.doFinal(padString(text).getBytes());
} catch (Exception e)
{
throw new Exception("[encrypt] " + e.getMessage());
}
return new String( encrypted );
}
public String decrypt(String code) throws Exception
{
if(code == null || code.length() == 0)
throw new Exception("Empty string");
Cipher cipher;
byte[] decrypted = null;
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
decrypted = cipher.doFinal(hexToBytes(code));
} catch (Exception e)
{
throw new Exception("[decrypt] " + e.getMessage());
}
return new String( decrypted );
}
private static byte[] hexToBytes(String hex) {
String HEXINDEX = "0123456789abcdef";
int l = hex.length() / 2;
byte data[] = new byte[l];
int j = 0;
for (int i = 0; i < l; i++) {
char c = hex.charAt(j++);
int n, b;
n = HEXINDEX.indexOf(c);
b = (n & 0xf) << 4;
c = hex.charAt(j++);
n = HEXINDEX.indexOf(c);
b += (n & 0xf);
data[i] = (byte) b;
}
return data;
}
private static String padString(String source)
{
char paddingChar = ' ';
int size = 16;
int x = source.length() % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++)
{
source += paddingChar;
}
return source;
}
And this is how I'm using it in my activity to test:
String encrypted = mcrypt.encrypt(jsonUser.toString());
String decrypted = mcrypt.decrypt(encrypted);
the encrypt method works fine, but the second throws an exception.
At last! I made it work! Thanks for all your suggestion. I would like to share the code just in case somebody get stuck like me:
JAVA
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class MCrypt {
private String iv = "fedcba9876543210";//Dummy iv (CHANGE IT!)
private IvParameterSpec ivspec;
private SecretKeySpec keyspec;
private Cipher cipher;
private String SecretKey = "0123456789abcdef";//Dummy secretKey (CHANGE IT!)
public MCrypt()
{
ivspec = new IvParameterSpec(iv.getBytes());
keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public byte[] encrypt(String text) throws Exception
{
if(text == null || text.length() == 0)
throw new Exception("Empty string");
byte[] encrypted = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
encrypted = cipher.doFinal(padString(text).getBytes());
} catch (Exception e)
{
throw new Exception("[encrypt] " + e.getMessage());
}
return encrypted;
}
public byte[] decrypt(String code) throws Exception
{
if(code == null || code.length() == 0)
throw new Exception("Empty string");
byte[] decrypted = null;
try {
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
decrypted = cipher.doFinal(hexToBytes(code));
} catch (Exception e)
{
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
public static String bytesToHex(byte[] data)
{
if (data==null)
{
return null;
}
int len = data.length;
String str = "";
for (int i=0; i<len; i++) {
if ((data[i]&0xFF)<16)
str = str + "0" + java.lang.Integer.toHexString(data[i]&0xFF);
else
str = str + java.lang.Integer.toHexString(data[i]&0xFF);
}
return str;
}
public static byte[] hexToBytes(String str) {
if (str==null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i=0; i<len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
}
return buffer;
}
}
private static String padString(String source)
{
char paddingChar = ' ';
int size = 16;
int x = source.length() % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++)
{
source += paddingChar;
}
return source;
}
}
HOW TO USE IT (JAVA)
mcrypt = new MCrypt();
/* Encrypt */
String encrypted = MCrypt.bytesToHex( mcrypt.encrypt("Text to Encrypt") );
/* Decrypt */
String decrypted = new String( mcrypt.decrypt( encrypted ) );
====================================================
PHP
<?php
class MCrypt
{
private $iv = 'fedcba9876543210'; #Same as in JAVA
private $key = '0123456789abcdef'; #Same as in JAVA
function __construct()
{
}
function encrypt($str) {
//$key = $this->hex2bin($key);
$iv = $this->iv;
$td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
mcrypt_generic_init($td, $this->key, $iv);
$encrypted = mcrypt_generic($td, $str);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return bin2hex($encrypted);
}
function decrypt($code) {
//$key = $this->hex2bin($key);
$code = $this->hex2bin($code);
$iv = $this->iv;
$td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
mcrypt_generic_init($td, $this->key, $iv);
$decrypted = mdecrypt_generic($td, $code);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return utf8_encode(trim($decrypted));
}
protected function hex2bin($hexdata) {
$bindata = '';
for ($i = 0; $i < strlen($hexdata); $i += 2) {
$bindata .= chr(hexdec(substr($hexdata, $i, 2)));
}
return $bindata;
}
}
HOW TO USE IT (PHP)
<?php
$mcrypt = new MCrypt();
#Encrypt
$encrypted = $mcrypt->encrypt("Text to encrypt");
#Decrypt
$decrypted = $mcrypt->decrypt($encrypted);
I'm guessing your keyspec and ivspec are not valid for decryption. I've typically transformed them into PublicKey and PrivateKey instances and then use the private key to decrypt.
I looked at the comments in the other answer. I ran into a similar problem trying to encrypt a large block of text using open SSL in php (on both sides). I imagine the same issue would come up in Java.
If you have a 1024 bit RSA key, you must split the incoming text into 117 byte chunks (a char is a byte) and encrypt each (you can concatenate them together). On the other end, you must split the encrypted data into 128 byte chunks and decrypt each. This should give you your original message.
Also note that http may not play friendly with the non-ASCII encrypted data. I base64 encode/decode it before and after transmission (plus you have to worry about additional urlencoding for the base64 change, but it is easy).
I'm not sure of your AES key length, but if it's 1024 bits the chunk length is probably the same. If it's not, you will have to divide the bits by 8 to find the byte chunk length coming out. I'm actually not sure how to get it coming in, unfortunately (maybe multiply by 117/128 ?)
Here's some php code:
class Crypto {
public function encrypt($key, $data) {
$crypto = '';
foreach (str_split($data, 117) as $chunk) {
openssl_public_encrypt($chunk, $encrypted, $key);
$crypto .= $encrypted;
}
return $crypto;
}
//Decrypt omitted. Basically the same, change 117 to 128.
/**##+
* Update data for HTTP transmission and retrieval
* Must be used on encrypted data, but also useful for any binary data
* (e.g. zip files).
*/
public function base64_encode($value) {
return rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
}
//String length must be padded for decoding for some reason
public function base64_decode($value) {
return base64_decode(str_pad(strtr($value, '-_', '+/')
, strlen($value) % 4, '=', STR_PAD_RIGHT));
}
/**##-*/
}