Moon
Moon

Reputation: 20012

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

Upvotes: 1

Views: 4560

Answers (4)

Moon
Moon

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

DarkSquirrel42
DarkSquirrel42

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

rossum
rossum

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

pcjuzer
pcjuzer

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

Related Questions