Reputation: 20012
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
Upvotes: 1
Views: 4560
Reputation: 20012
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;
}
}
}
Upvotes: 0
Reputation: 10257
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)
Upvotes: 2
Reputation: 15685
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.
Upvotes: 1
Reputation: 2824
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.
Upvotes: 0