1

I am making an android application in which I am supposed to encrypt the passwords I take from the user and send it to my app engine. I want to the use the AES technique with a Base64 key. I am new to encryption/decryption so i used the code asked in this question. I changed the key and replaced it with mine. This is my code:

public String encrypt(String dataToEncrypt)
            throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        // I'm using AES encription

        if (!dataToEncrypt.equals("")) {
            String key = "rEqrHrhdd9I1sg==";

            Cipher c = Cipher.getInstance("AES");
            SecretKeySpec k;
            try {
                k = new SecretKeySpec(key.getBytes(), "AES");
                c.init(Cipher.ENCRYPT_MODE, k);
            } catch (Exception e) {
                e.printStackTrace();
            }

            return new String(c.doFinal(Base64.decode(dataToEncrypt, 0)));
        }
        return "";
    }

But sometimes I get an error "java.lang.IllegalArgumentException: bad base-64" when i try to encrypt certain strings, say "asdasdasd" gives this error when i am encrypting it. Can anyone please tell me what the problem is??
-Thanks in advance

Community
  • 1
  • 1
Antrromet
  • 15,294
  • 10
  • 60
  • 75
  • I've given the answer as a new code sample, but not every string using the base 64 character set is automatically base 64, if the last character has some low order bits set and the string is not divisable by 4 you've got problems. You might, in addition, have to use the base 64 padding character (`'='`). – Maarten Bodewes Feb 10 '12 at 18:09
  • How are you faring Antrromet, are you getting to a solution? I'm sorry if the discussion got a bit hairy :) – Maarten Bodewes Feb 12 '12 at 15:16
  • Hey Owlstead, am really pissed by experimenting with encryption decryption, its not my cup of tea. So i am using hashing instead to store my passwords. – Antrromet Feb 13 '12 at 04:56
  • That's probably better anyway. You might want to check out PBKDF2 or bcrypt to store them even more safely (they protect against brute force attacks and rainbow tables). Of course, they are also slightly more difficult to use. – Maarten Bodewes Feb 13 '12 at 19:31

4 Answers4

3

Try this as an example on how to use Strings for keys and messages. At least it uses the right (character) encoding, uses CBC mode and PKCS5/7 padding. Note that there are a lot of issues with sending passwords encrypted to a server. Normally, security should be achieved by using SSL for confidentiallity and bcrypt or PBKDF2 on the server (but this has been covered again and again on stackoverflow).

Note that the code below does not provide integrity checks or authenticity .

public static String encrypt(final String plainMessage,
        final String symKeyHex) {
    final byte[] symKeyData = DatatypeConverter.parseHexBinary(symKeyHex);

    final byte[] encodedMessage = plainMessage.getBytes(Charset
            .forName("UTF-8"));
    try {
        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // generate random IV using block size (possibly create a method for
        // this)
        final byte[] ivData = new byte[blockSize];
        final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
        rnd.nextBytes(ivData);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        cipher.init(Cipher.ENCRYPT_MODE, symKey, iv);

        final byte[] encryptedMessage = cipher.doFinal(encodedMessage);

        // concatenate IV and encrypted message
        final byte[] ivAndEncryptedMessage = new byte[ivData.length
                + encryptedMessage.length];
        System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
        System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage,
                blockSize, encryptedMessage.length);

        final String ivAndEncryptedMessageBase64 = DatatypeConverter
                .printBase64Binary(ivAndEncryptedMessage);

        return ivAndEncryptedMessageBase64;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during encryption", e);
    }
}

public static String decrypt(final String ivAndEncryptedMessageBase64,
        final String symKeyHex) {
    final byte[] symKeyData = DatatypeConverter.parseHexBinary(symKeyHex);

    final byte[] ivAndEncryptedMessage = DatatypeConverter
            .parseBase64Binary(ivAndEncryptedMessageBase64);
    try {
        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // retrieve random IV from start of the received message
        final byte[] ivData = new byte[blockSize];
        System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        // retrieve the encrypted message itself
        final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length
                - blockSize];
        System.arraycopy(ivAndEncryptedMessage, blockSize,
                encryptedMessage, 0, encryptedMessage.length);

        cipher.init(Cipher.DECRYPT_MODE, symKey, iv);

        final byte[] encodedMessage = cipher.doFinal(encryptedMessage);

        // concatenate IV and encrypted message
        final String message = new String(encodedMessage,
                Charset.forName("UTF-8"));

        return message;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (BadPaddingException e) {
        // you'd better know about padding oracle attacks
        return null;
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during decryption", e);
    }
}
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • What is the alternative to use for `DatatypeConverter` for Android. I tried using Base64.decode method, but its not giving the intended result.. – YuDroid Feb 18 '14 at 12:35
  • I cannot see what is going on at your machine, YuDroid. Please create a new question with the code of `DatatypeConverter` and the one with `Base64.decode`, input & output so we can see the differences. – Maarten Bodewes Feb 18 '14 at 18:43
0

Look at my answer here Android database encryption. It contains 2 files that you can include in any of your applications that require data storage to be encrypted. There is implemented method that make it easier to convert the byte array data into printable Base64 data and vice versa. Used the AES algorithm with Cipher Block Chaining (CBC) encryption mode and PKCS#5 padding.

Community
  • 1
  • 1
Plo_Koon
  • 2,953
  • 3
  • 34
  • 41
0

Hi i rewrite the owlstead java methods example without DatatypeConverter and with apache commons.

public static String encrypt(final String plainMessage,
        final String symKeyHex) {


    try {

    final byte[] symKeyData = Hex.decodeHex(symKeyHex.toCharArray());

    final byte[] encodedMessage = plainMessage.getBytes(Charset.forName("UTF-8"));

        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // generate random IV using block size (possibly create a method for
        // this)
        final byte[] ivData = new byte[blockSize];
        final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
        rnd.nextBytes(ivData);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        cipher.init(Cipher.ENCRYPT_MODE, symKey, iv);

        final byte[] encryptedMessage = cipher.doFinal(encodedMessage);

        // concatenate IV and encrypted message
        final byte[] ivAndEncryptedMessage = new byte[ivData.length
                + encryptedMessage.length];
        System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
        System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage,
                blockSize, encryptedMessage.length);

        final String ivAndEncryptedMessageBase64 = Base64.encodeBase64String(ivAndEncryptedMessage);

        return ivAndEncryptedMessageBase64;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during encryption", e);
    } catch (DecoderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return "";

}

public static String decrypt(final String ivAndEncryptedMessageBase64,
        final String symKeyHex) {

    try {
        final byte[] symKeyData = Hex.decodeHex(symKeyHex.toCharArray());
        final byte[] ivAndEncryptedMessage = Base64.decodeBase64(ivAndEncryptedMessageBase64);


        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // retrieve random IV from start of the received message
        final byte[] ivData = new byte[blockSize];
        System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        // retrieve the encrypted message itself
        final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length
                - blockSize];
        System.arraycopy(ivAndEncryptedMessage, blockSize,
                encryptedMessage, 0, encryptedMessage.length);

        cipher.init(Cipher.DECRYPT_MODE, symKey, iv);

        final byte[] encodedMessage = cipher.doFinal(encryptedMessage);

        // concatenate IV and encrypted message
        final String message = new String(encodedMessage,
                Charset.forName("UTF-8"));

        return message;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (BadPaddingException e) {
        // you'd better know about padding oracle attacks
        return null;
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during decryption", e);
    } catch (DecoderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return "";
}

You can not even use this on android because you could have some problem with Base64 Class. On android you could use the following methods that use Base64 android class:

public static String encrypt(final String plainMessage,
                             final String symKeyHex) {


    try {

        final byte[] symKeyData = Hex.decodeHex(symKeyHex.toCharArray());

        final byte[] encodedMessage = plainMessage.getBytes(Charset.forName("UTF-8"));

        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // generate random IV using block size (possibly create a method for
        // this)
        final byte[] ivData = new byte[blockSize];
        final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
        rnd.nextBytes(ivData);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        cipher.init(Cipher.ENCRYPT_MODE, symKey, iv);

        final byte[] encryptedMessage = cipher.doFinal(encodedMessage);

        // concatenate IV and encrypted message
        final byte[] ivAndEncryptedMessage = new byte[ivData.length
                + encryptedMessage.length];
        System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
        System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage,
                blockSize, encryptedMessage.length);

        //final String ivAndEncryptedMessageBase64 = Base64.encodeBase64String(ivAndEncryptedMessage);
        final String ivAndEncryptedMessageBase64 = Base64.encodeToString(ivAndEncryptedMessage,Base64.DEFAULT);

        return ivAndEncryptedMessageBase64;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during encryption", e);
    } catch (DecoderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return "";

}

public static String decrypt(final String ivAndEncryptedMessageBase64,
                             final String symKeyHex) {


    try {

        final byte[] symKeyData = Hex.decodeHex(symKeyHex.toCharArray());
        //final byte[] ivAndEncryptedMessage = Base64.decodeBase64(ivAndEncryptedMessageBase64);
        final byte[] ivAndEncryptedMessage = Base64.decode(ivAndEncryptedMessageBase64,Base64.DEFAULT);

        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // retrieve random IV from start of the received message
        final byte[] ivData = new byte[blockSize];
        System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        // retrieve the encrypted message itself
        final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length
                - blockSize];
        System.arraycopy(ivAndEncryptedMessage, blockSize,
                encryptedMessage, 0, encryptedMessage.length);

        cipher.init(Cipher.DECRYPT_MODE, symKey, iv);

        final byte[] encodedMessage = cipher.doFinal(encryptedMessage);

        // concatenate IV and encrypted message
        final String message = new String(encodedMessage,
                Charset.forName("UTF-8"));

        return message;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (BadPaddingException e) {
        // you'd better know about padding oracle attacks
        return null;
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during decryption", e);
    } catch (DecoderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return "";
}

Hope this help!

alessandro
  • 119
  • 7
0

simplecrypto.java

     import java.security.SecureRandom;
     import javax.crypto.Cipher;
     import javax.crypto.KeyGenerator;
     import javax.crypto.SecretKey;
     import javax.crypto.spec.SecretKeySpec;

     public class SimpleCrypto {

public  String encrypt(String seed, String cleartext) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] result = encrypt(rawKey, cleartext.getBytes());
        return toHex(result);
}

public  String decrypt(String seed, String encrypted) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] enc = toByte(encrypted);
        byte[] result = decrypt(rawKey, enc);
        return new String(result);
}

//done
private  byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
        sr.setSeed(seed);
    kgen.init(128, sr); // 192 and 256 bits may not be available
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
}


private  byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(clear);
        return encrypted;
}

private  byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    byte[] decrypted = cipher.doFinal(encrypted);
        return decrypted;
}

public  String toHex(String txt) {
        return toHex(txt.getBytes());
}
public  String fromHex(String hex) {
        return new String(toByte(hex));
}

public  byte[] toByte(String hexString) {
        int len = hexString.length()/2;
        byte[] result = new byte[len];
        for (int i = 0; i < len; i++)
                result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
        return result;
}

public  String toHex(byte[] buf) {
        if (buf == null)
                return "";
        StringBuffer result = new StringBuffer(2*buf.length);
        for (int i = 0; i < buf.length; i++) {
                appendHex(result, buf[i]);
        }
        return result.toString();
}
private final static String HEX = "0123456789ABCDEF";
private  void appendHex(StringBuffer sb, byte b) {
        sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}

  }

and in activity please put following code :

SimpleCrypto simpleCrypto = new SimpleCrypto();
    String s = "";
    try {
        s = simpleCrypto.encrypt("abc", "xyz");
    } catch (Exception e) {
        e.printStackTrace();
    }

abc is the text to be encrypt and xyz is the key for encryption

Ramesh Solanki
  • 2,961
  • 4
  • 28
  • 44
  • let me know if u have any doubt – Ramesh Solanki Feb 07 '12 at 10:58
  • yes this works for me. But i have a doubt. Actually my friends are also working on the same encryption thing, but they are getting a different result than mine. Could you please tell me exactly which encryption/decryption technique is this? – Antrromet Feb 07 '12 at 11:18
  • Is there a particular format of the encrypted string?? and what are the parameters that i need to send to decrypt()?? Is decrypt(,) correct? – Antrromet Feb 07 '12 at 11:19
  • yea i understand that, but which technique is this?? I mean even my friends working on iOS are using the same key value as mine but they are getting a different result. – Antrromet Feb 07 '12 at 11:25
  • EVERYTHING is wrong in this answer. The key derivation, there are encoding issues, the list goes on. – Maarten Bodewes Feb 10 '12 at 17:55
  • Ramesh: you cannot continue like this, you need to discuss with your friends the exact protocol to use. This should include the cipher (AES with 128 bit key size, OK), then the mode, the kind of padding to be used, and the (character)-encoding of both the plain text and cipher text. CBC with an IV prepended would be a good starter (see my answer). Only after knowing all the parameters can you start developing (maybe you can share this in code, but it needs to be known beforehand). – Maarten Bodewes Feb 11 '12 at 21:14