Encrypt in python and decrypt in Java with AES-CFB - java

I am aware of a question very similar to this (How do I encrypt in Python and decrypt in Java?) but I have a different problem.
My problem is, I am not able to decrypt in Java correctly. Despite using the correct key and IV, I still get garbage characters after decryption. I don't have any compile/run-time errors or exceptions in Java so I believe I am using the right parameters for decryption.
Python Encryption Code -
from Crypto.Cipher import AES
import base64
key = '0123456789012345'
iv = 'RandomInitVector'
raw = 'samplePlainText'
cipher = AES.new(key,AES.MODE_CFB,iv)
encrypted = base64.b64encode(iv + cipher.encrypt(raw))
Java Decryption Code -
private static String KEY = "0123456789012345";
public static String decrypt(String encrypted_encoded_string) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
String plain_text = "";
try{
byte[] encrypted_decoded_bytes = Base64.getDecoder().decode(encrypted_encoded_string);
String encrypted_decoded_string = new String(encrypted_decoded_bytes);
String iv_string = encrypted_decoded_string.substring(0,16); //IV is retrieved correctly.
IvParameterSpec iv = new IvParameterSpec(iv_string.getBytes());
SecretKeySpec skeySpec = new SecretKeySpec(KEY.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
plain_text = new String(cipher.doFinal(encrypted_decoded_bytes));//Returns garbage characters
return plain_text;
} catch (Exception e) {
System.err.println("Caught Exception: " + e.getMessage());
}
return plain_text;
}
Is there anything obvious that I am missing?

The Cipher Feedback (CFB) mode of operation is a family of modes. It is parametrized by the segment size (or register size). PyCrypto has a default segment size of 8 bit and Java (actually OpenJDK) has a default segment size the same as the block size (128 bit for AES).
If you want CFB-128 in pycrypto, you can use AES.new(key, AES.MODE_CFB, iv, segment_size=128). If you want CFB-8 in Java, you can use Cipher.getInstance("AES/CFB8/NoPadding");.
Now that we have that out the way, you have other problems:
Always specify the character set you're using, because it can change between different JVMs: new String(someBytes, "UTF-8") and someString.getBytes("UTF-8"). When you do, be consistent.
Never use a String to store binary data (new String(encrypted_decoded_bytes);). You can copy the bytes directly: IvParameterSpec iv = new IvParameterSpec(Arrays.copyOf(encrypted_decoded_bytes, 16)); and cipher.doFinal(Arrays.copyOfRange(encrypted_decoded_bytes, 16, encrypted_decoded_bytes.length)).
In Java, you're assuming that the IV is written in front of the ciphertext and then encoded together, but in Python, you're never doing anything with the IV. I guess you posted incomplete code.
It is crucial for CFB mode to use a different IV every time if the key stays the same. If you don't change the IV for every encryption, you will create a multi-time pad which enables an attacker to deduce the plaintext even without knowing the key.

Related

How to encrypt text into plain text strings only

I have to implement basic encryption in my program. I can use Base64 it was rejected by the client. So I am using the following methods. The problem which I am facing is the there are special characters in the encrypted which are resulting in exceptions. Can I change this code to somehow encrypt into plain text without special characters.
protected static byte[] encrypt(String text)
{
try
{
String key = "6589745268754125";
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(text.getBytes());
return encrypted;
}
catch(Exception ex)
{
WriteLog("Encryption Failed");
WriteLog(ex.getMessage());
return null;
}
}
protected static String decrypt(byte[] pass)
{
try
{
String key = "6589745268754125";
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// decrypt the text
cipher.init(Cipher.DECRYPT_MODE, aesKey);
String decrypted = new String(cipher.doFinal(pass));
return decrypted;
}
catch(Exception ex)
{
WriteLog("Encryption Failed");
WriteLog(ex.getMessage());
return null;
}
}
The exception message says "Given final block not properly padded"
javax.crypto.BadPaddingException: Given final block not properly padded
so, basically you don't know about encryption and have the problem that your client wants encryption
ok, a quick headsup:
encoding: transforming an input to an output that holds identical information but in another representation ... ex: 1,2,3 -> a,b,c
as you can see the output looks differently but holds the same information
please note that no secret information is necessary to encode/decode
encryption: might look similar at first glance but here you need some secrets ... an encryption takes 2 inputs ... a secret and the input data
the resulting output can be decrypted, but ONLY if you have the corresponding secret
if your client wants you to encrypt something, make sure that thing can be represented as bytes ... encrypting a string... not good... encrypting a string that has been transformed into < insert arbitrary byte encoding here, for example unicode > ... ok
encryptions usually handle bytes (let's not care about historic ciphers here)
when you decide for an encryption/cipher you have to know that there are essentially 2 distinct groups: symetric and asymetric
symetric: the same key (read secret) you use to encrypt will be needed for decryption
asymetric: there are keypairs consisting of a public and a private part (public/private key) the public part is used for encryption, the private part is used for decryption ... makes no sense unless you have different parties that need to exchange keys
asymetric ciphers are usually used to encrypt decrypt the keys for symetric ciphers because they are SLOW while symetric ciphers usually are FAST
asymetric ciphers are not intended to encrypt large amounts of data
symetric ciphers are intended for bulk data
if your goal is just to keep an information encrypted while it is laying around on a harddisk, a symetric cipher is what you want
you will need a key for the cipher to operate ... and... you will have the problem where to store it ... so if you can, have the user enter a sufficiently complex password ... use the password and a function called PBKDF2 with a sufficiently high iteration count (sufficiently high= increase this number until the process takes either a few seconds if you only need this on startup, or until your users start complaining about the delay) to make binary key from the password.
use this key for AES in GCM mode (symetric cipher)
the cipher will want something called IV or initialization vector ...
the iv is no secret, you may prepend this thing to your ciphertext as clear text information
the iv needs to be the size of one block of your cipher, so in the case of AES 128 bit = 16 byte
so your IV when encrypting is a 16 byte (unique) random number (means that you may not use an IV two times or more: persist the used IVs and when getting a new one, check if it was already stored, if yes startover IV generation, if no, store it and then use it)
when decrypting, read the prepended cleartext IV from your file (first 16 byte)
if you just want to store the ciphertext on disk, write it into a binary file
if the file has to contain only printable text apply an encoding like base16/32/64 before writing your bytes to the file and decode into a byte array before decrypting (unless your data is too big for that, then you will have to find/write a stream wrapper that will add/strip encoding for you)
If the client doesn't like Base64, then try Base32 or Base16 (= hex). They are less common but well defined alternatives to Base64.
You might also find out exactly why the client doesn't want you to use Base64.
You should Base64 the encrypted content. It's usual technique by the way.
I guess the client's problem wasn't Base64 format itself but the fact, that Base64 isn't (a strong) encryption.
The problem was padding. I had use AES/CBC/NoPadding and make sure that my strings are multiple of 16 bytes. So in addition to changing the ecryption and decryption I had to add two methods. One to add \0 i.e. implicit null terminators to the end end of the text to make it a multiple of 16 and another to remove them after decryption. So the final version is like this.
public class crypto {
static String IV = "AAAAAAAAAAAAAAAA";
static String plaintext = "my non padded text";
static String encryptionKey = "0123456789abcdef";
public static void main(String[] args)
{
byte[] cipher = encrypt(plaintext);
String decrypted = decrypt(cipher);
}
protected static String covertto16Byte(String plainText)
{
while(plainText.length()%16 != 0)
plainText += "\0";
return plainText;
}
protected static String removePadding(String plainText)
{
return plainText.replace("\0","");
}
protected static byte[] encrypt(String plainText)
{
try
{
String _plaintText_16 = covertto16Byte(plainText);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return cipher.doFinal(_plaintText_16.getBytes("UTF-8"));
} catch (Exception ex)
{
//catch mechanism
return null;
}
}
protected static String decrypt(byte[] cipherText)
{
try
{
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return removePadding(new String(cipher.doFinal(cipherText), "UTF-8"));
} catch (Exception ex)
{
//catch mechanism
return null;
}
}
}

IllegalBlocksizeException - How to use Base64 to solve

I am having some troubles with the following code - I seem to be getting an IllegalBlocksizeException and am unsure what it is that I maybe doing incorrectly here? Would it be possible to get some advice / pointers?
Thanks
public class Encryption
{
private SecretKeyFactory factory;
private SecretKey tmp;
private SecretKey secret;
private Cipher cipher;
private byte[] iv;
private byte[] cipherText;
private final KeySpec spec = new PBEKeySpec("somepassword".toCharArray(), SALT, 65536, 256);
private static final byte[] SALT = {(byte)0xc3, (byte)0x23, (byte)0x71, (byte)0x1c, (byte)0x2e, (byte)0xc2, (byte)0xee, (byte)0x77};
public Encryption()
{
try
{
factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
tmp = factory.generateSecret(spec);
secret = new SecretKeySpec(tmp.getEncoded(), "AES");
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public String encrypt(String valueToEncrypt) throws Exception
{
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv));
cipherText = cipher.doFinal(Base64.decodeBase64(valueToEncrypt.getBytes()));
return Base64.encodeBase64String(cipherText);
}
public String decrypt(String encryptedValueToDecrypt) throws Exception
{
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
return new String(cipher.doFinal(new Base64().encode(encryptedValueToDecrypt.getBytes())));
}
public static void main(String[] args ) throws Exception
{
Encryption manager = new Encryption();
String encrypted = manager.encrypt("this is a string which i would like to encrypt");
System.out.println(encrypted);
String decrypted = manager.decrypt(encrypted);
System.out.println(decrypted);
System.out.println(encrypted.equals(decrypted));
}
}
The exception is as follows
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:750)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
at encrypt.Encryption.decrypt(Encryption.java:52)
at encrypt.Encryption.main(Encryption.java:60)
The only approach to begin with the implementation of cryptographic algorithms, from the functional point of view (please keep in mind that a working code is not necessarily a secure one, and a lot of thought should come in that direction), is incremental: first try raw AES with a fixed key, then add the key generated by PBKDF2 and only later Base64. The latter is just an encoding tool and should be the easiest part of the process.
But let's take a look to the code:
1. The initialization seems fine, if your goal is to generate the key out of a password.
2. During the decryption, this line stands off:
cipherText = cipher.doFinal(Base64.decodeBase64(valueToEncrypt.getBytes()));
valueToEncrypt is a readable string, but you're trying to decrypt it. Since it has only lowercase letters and spaces, it might not trigger an error, but you're trying to base64-decode something that hasn't been base64-encoded. It would make more sense to try:
cipherText = cipher.doFinal(valueToEncrypt.getBytes());
Then the cipherText can be base64-encoded.
For the decryption part, undo the operations in encryption in the reverse order. If you encrypted and then base64-encoded, then base64-decode first and then decrypt.
As a final recommendation: think modular. Encode in one line and encrypt in another, so if you want to remove or add a layer you just have to toggle the comments on one line.
You have reversed the base-64 encoding and decoding operations. Base-64 takes raw bytes and makes them into printable text. You can encode the output of an encryption operation to make it printable. But then you will need to base‑64–decode that text before trying to decrypt it.
This part of your decrypt() method is causing the problem:
cipher.doFinal(new Base64().encode(encryptedValueToDecrypt.getBytes()))
That should be:
cipher.doFinal(Base64.decodeBase64(encryptedValueToDecrypt.getBytes()))
Asking for "pointers" is pretty open-ended. The best pointer I can give you: don't write this code yourself. Choose a package that provides a higher-level API, selecting high-security algorithms and applying them according to best practices. You don't know what you are doing, and you won't be able to write secure code. But using a high quality, open source library might help you begin to learn more about encryption.
You probably should base64 decode encryptedValueToDecrypt before you decrypt it.

AES-256: IV vector misunderstanding between Ruby and Java implementations

I have "inherited" a Ruby on Rails app, and I must translate this app from Ruby to Java, and the most important thing, I don't have contact with the creator.
My problem is with the IV vector in AES-256 authentication. Ruby app uses AESCrypt gem to encrypt and decrypt user's password. It works fine, and I have already some thousands of users in DB.
The problem is when I try to do the same in Java (I've already updated JCE to allow 256bit key lenght). The Key and the IV are writen as binary strings in ruby source code (see bellow), and when I try to use it in Java I get a exception which say that the IV lenght must be 16 bytes long (I know that it must be 16 bytes long, but the binary string in Ruby has 32 characters).
Ruby code (works fine):
require 'openssl'
require 'digest/md5'
require 'base64'
module AESCrypt
KEY = "AB1CD237690AF13B6721AD237A"
IV = "por874hyufijdue7w63ysxwet4320o90"
TYPE = "AES-256-CBC"
def AESCrypt.key(key)
key = Digest::MD5.hexdigest(key)
key.slice(0..32)
end
# Encrypts a block of data given an encryption key and an
# initialization vector (iv). Keys, iv's, and the data returned
# are all binary strings. Cipher_type should be "AES-256-CBC",
# "AES-256-ECB", or any of the cipher types supported by OpenSSL.
# Pass nil for the iv if the encryption type doesn't use iv's (like
# ECB).
#:return: => String
#:arg: data => String
#:arg: key => String
#:arg: iv => String
#:arg: cipher_type => String
def AESCrypt.encrypt(data)
return nil if data.nil?
return data if data.blank?
aes = OpenSSL::Cipher::Cipher.new(TYPE)
aes.encrypt
aes.key = AESCrypt.key(KEY)
aes.iv = IV if IV != nil
result = aes.update(data) + aes.final
Base64.encode64(result)
end
end
and this is my Java code (it should do the same, seems that works with a 16 chars/bytes IV):
public static void main(String[] args) throws UnsupportedEncodingException {
String KEY = "AB1CD237690AF13B6721AD237A";
String IV = "por874hyufijdue7w63ysxwet4320o90";
SecretKeySpec key = generateKey(KEY);
String message = "password";
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] ciphedText = cipher.doFinal(message.getBytes());
String encoded = Base64.encodeBase64String(ciphedText);
System.out.println("ENCRYPTED text= " + encoded);
}
public static SecretKeySpec generateKey(final String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
final MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] bytes = password.getBytes("UTF-8");
digest.update(bytes, 0, bytes.length);
byte[] key = digest.digest();
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
return secretKeySpec;
}
And I'm getting this exception (obviously):
java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long
at com.sun.crypto.provider.CipherCore.init(CipherCore.java:516)
at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:339)
at javax.crypto.Cipher.implInit(Cipher.java:801)
at javax.crypto.Cipher.chooseProvider(Cipher.java:859)
at javax.crypto.Cipher.init(Cipher.java:1370)
at javax.crypto.Cipher.init(Cipher.java:1301)
at com.javi.test.security.Test.main(Test.java:129)
I guess my problem is the way I convert the IV java string in byte[]. I think that openSSL code in ruby is unpacking (or doing something internally) the 32 bytes of the IV to 16 bytes. I have tried a lot of things, but I'm going crazy.
Anyone had the same problem or figure out where could be my problem?
I have posted the encryption code but I hace the same issue with decryption.
Thanks in advance, I'll be very grateful with every answer. :)
First, your IV is not actually iv, IV should be HEX encoded, but you have ASCII string "por874hyufijdue7w63ysxwet4320o90", may be it is some how encoded?
Second, IV.getBytes() will transofr IV's each character to hex encoding like p = 0x70, o = 0x6F, r = 0x72, etc...
It is not a useful answer, but may be hint.
Actually IV must be the same length as block cipher single block length. You have 32 bytes long IV itself, if you make IV.getBytes() IV length should match the cipher block length

Decrypting a byte[] back to String without loss of data

I have written a small application to encrypt and decrypt Strings using AES. Here is the code:
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class AesEncryptionTest {
static IvParameterSpec initialisationVector = generateInitialisationVector();
static SecretKey encryptionKey = generateKey();
static String plainText = "test text 123\0\0\0";
public static void main(String [] args) {
try {
System.out.println("Initial Plain Text = " + plainText);
byte[] encryptedText = encrypt(plainText, encryptionKey);
System.out.println("Encrypted Text = " + encryptedText);
String decryptedText = decrypt(encryptedText, encryptionKey);
System.out.println("Decrypted Text = " + decryptedText);
} catch (Exception e) {
e.printStackTrace();
}
}
public static byte[] encrypt(String plainText, SecretKey encryptionKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey, initialisationVector);
return cipher.doFinal(plainText.getBytes("UTF-8"));
}
public static String decrypt(byte[] encryptedText, SecretKey encryptionKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
cipher.init(Cipher.DECRYPT_MODE, encryptionKey, initialisationVector);
return new String(cipher.doFinal(encryptedText),"UTF-8");
}
public static SecretKey generateKey() {
SecretKey secretKey = null;
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
secretKey = keyGenerator.generateKey();
} catch (NoSuchAlgorithmException ex) {
// Whine a little
}
return secretKey;
}
public static IvParameterSpec generateInitialisationVector() {
byte[] initVector = new byte[16];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(initVector);
return new IvParameterSpec(initVector);
}
}
Output:
Initial Plain Text = test text 123
Encrypted Text = [B#407dcb32
Decrypted Text = test text 123
My main areas of concern are around encrypting into a byte array and decrypting back to a String. I know that this can introduce unexpected behaviour and loss of data. While this has not been observed in my testing, could anyone suggest any changes that would help combat this? I think I have this covered by ensuring UTF-8 is used both ways.
If anyone see's any other red flags with my code and how I have done this, I'm open to criticism/suggestions.
Many thanks!
You're calling toString() on a byte[] which is never a good idea. Basically it's not giving you any useful information.
If you want to convert arbitrary binary data into a string, I'd suggest using hex or base64, both of which are covered elsewhere. There's no indication that you've actually lost any information here in the encryption/decryption - the problem is your display of the encrypted data. So long as you don't try to treat that as simple encoded text data (because it isn't) you should be fine. In particular, your code is already specifying UTF-8 as the conversion from the original text to unencrypted binary data, and vice versa - so that's safe.
If you don't need to convert the byte array to a string, it's simplest to avoid doing so in the first place. (For example, you could write it to a file still in the binary form very simply, then load it back into a byte array later.)
You asked for other red flags, so I'll give you a few pointers regarding the crypto:
Generally you don't have to provide the provider name when you use an algorithm name. Specifying the provider makes your code less portable.
It is better to use a standardized padding mode such as "/PKCS5Padding" (identical to PKCS#7 padding in Java). If you want to use the current padding mode you can configure the Bouncy Castle provider and specify "/ZeroBytePadding". This padding mode does not work correctly for plaintext that ends with zero valued bytes.
You store the IV in the same class variable as the key. I know this is just test code, but normally the IV need to be send or established at both sides. The most common way to use the same key at both sides is to prefix the IV to the ciphertext.
The size of the IV depends on the cipher. It is always 16 for AES, but you may want to make the IV size configurable or use the Cipher.getBlockSize() method.
Use GCM mode (available since 1.8) encryption if you also want authenticity/integrity and protection against padding oracle attacks.
You should use a fresh, random IV for each encrypt, instead of generating an IV just once.
the way to make sure the conversion is without loss is to use the same Charset when converting back and forth as you do.
Creating a string of the encrypted data is however not safe for further use; it can contain any and all sequences of bytes and might not fit into whatever Charset you originally used (you're not making this error, just pointing it out).
You're also printing the hashcode of the byte[] mid way in the code, not the individual bytes.

Using triple des(3des) of decrypt in java,get error of"javax.crypto.IllegalBlockSizeException: last block incomplete in decryption"

I use the code like 3des-encryption-decryption-in-java,but when I use decrypt it,it got a error like this
javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
07-17 11:27:27.580: WARN/System.err(22432): at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCipher.java:705)
07-17 11:27:27.580: WARN/System.err(22432): at javax.crypto.Cipher.doFinal(Cipher.java:1111)
But if I change final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding"); to final Cipher decipher = Cipher.getInstance("DESede/CFB/NoPadding");,the method can run but got a wrong result (the mode is different from server).
So I want to know the reason about it.
The decrypt method:
public static String decrypt(byte[] message) throws Exception {
final MessageDigest md = MessageDigest.getInstance("SHA-1");
final byte[] digestOfPassword = md.digest(token.getBytes("utf-8"));
final byte[] keyBytes = Arrays.copyOf(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");
// final Cipher decipher = Cipher.getInstance("DESede/CFB/NoPadding");
decipher.init(Cipher.DECRYPT_MODE, key, iv);
final byte[] plainText = decipher.doFinal(message);
return new String(plainText, "UTF-8");
}
The encrypt method:
public static byte[] encrypt(String message) throws Exception {
final MessageDigest md = MessageDigest.getInstance("SHA-1");
final byte[] digestOfPassword = md.digest(token
.getBytes("utf-8"));
final byte[] keyBytes = Arrays.copyOf(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, new SecureRandom(new byte[5]));
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
final byte[] plainTextBytes = message.getBytes("utf-8");
final byte[] cipherText = cipher.doFinal(plainTextBytes);
return cipherText;
}
There are many possibilitiesThe most common is if you atr encoding the key as a String, especially without specifying the character encoding. If you want to do this, use Base-64, which is designed to encode any binary data, rather than a character encodingAlso make sure that source platform and target platform encoding should be same.As you are using UTF-8 here and then on the other en , UTF-8 must be usedNow have a look under the facts which you are telling that code is running with final Cipher decipher = Cipher.getInstance("DESede/CFB/NoPadding"); but not with final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
While Decryption, you must know the padding size and mode in which you have selected at encryption time.As you are saying that when you use CBC mode than it throws exception but when you changed it to CFB then it got able to run.In this case you need to make sure which mode you are using at encrytpion time.
As a side note: CBC, OFB and CFB are identical, however OFB/CFB is better because you only need encryption and not decryption, which can save code space.
CBC(Cipher Block Chaining) is used where the data goes through the AES function, and feedback is applied to modify the pre-encrypted data, so that repeated plain data does not yield the same encrypted data. Data can only be processed in blocks which match the block-size of the underlying encryption function (so 128-bit blocks on the case of AES), and synchronisation at this block level must be provided between the encrypting and decrypting engines, otherwise data will be indecipherable
CFB(Cipher FeedBack mode) is also a common mode, and offers the possibility of making an underlying block cipher work like a stream cipher; ie. so that the data being processed can be a stream of shorter values (for example bytes or even individual bits) rather than being processed only as much larger blocks.In CFB mode, the data itself does not go through the AES engine, but gets XORed with a value which the AES engine generates from previous message history. This means that the latency through the CFB function can be minimised, as the only processing applied to the data is an XOR function. Data widths can be set to any size up to the underlying cipher block size, but note that throughput decreases as the widths get smaller in the ratio of the data width to the block size.(Side note ended :D)
If you encrypt using Cipher-Feedback (CFB) or Output-Feedback (OFB) or counter (CTR) modes then the ciphertext will be the same size as the plaintext and so padding is not required. Be careful, though, when using these modes, because the initialisation vectors (IV) must be unique.
Similarly, encrypting using a stream cipher like RC4 or PC1 does not require padding.
Now if we investigate more critically than you should take care about the block size and padding size(already mentioned above).Now the first thing you need to make sure is that the padding size defined by your encryption algorithm.As I mentioned that in CFB case padding is not required so first try it without giving padding.if issue still resides then check either it is pkcs5 or pkcs7.Try your code by setting decrytpion padding size to pkcs7.If it is pkcs7 then I guess it should work with CBC too.I recommend you to read Using Padding in Encryption As a additional information
PKCS#5 padding is defined in RFC 2898 (PKCS #5: Password-Based Cryptography Specification Version 2.0).
PKCS5 padding is a padding scheme for extending arbitrary data to match the block-size of a block cipher in a way that allows the receiving end to reliably remove the padding.
PKCS#7 (CMS, RFC 3369) defines a padding scheme, but it is an extension of PKCS#5 padding for block ciphers that have more than 8 bytes for block.

Categories

Resources