0

I'm working on a Android project that uses the AES algorithm (Rijndael) to encrypt and decrypt information trafficked.

WS I consume has a fixed key for encryption and decryption. So I have to have the same key in the source code.

However, this key undergoes a treatment to be subsequently used to encrypt / decrypt. The problem is that the key is not going through proper treatment. The reason: special characters. I tried using other keys without special characters, and it worked perfectly.

Here is an excerpt of the algorithm below:

final String KEY_GENERATION_ALG = "d(*Mu96p@lg91¨%0c*f7&d^`pkçly$f7";
    final int HASH_ITERATIONS = 10000;
    final int KEY_LENGTH = 256;

    char[] humanPassphrase = { 'P', 'e', 'r', ' ', 'v', 'a', 'l', 'l', 'u',
            'm', ' ', 'd', 'u', 'c', 'e', 's', ' ', 'L', 'a', 'b', 'a',
            'n', 't' };
    byte[] salt = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE,
            0xF }; 

    PBEKeySpec myKeyspec = new PBEKeySpec(humanPassphrase, salt, HASH_ITERATIONS, KEY_LENGTH);
    SecretKeyFactory keyfactory = null;
    SecretKey sk = null;
    SecretKeySpec skforAES = null;

    try {
        keyfactory = SecretKeyFactory.getInstance(KEY_GENERATION_ALG);
        sk = keyfactory.generateSecret(myKeyspec);

    } catch (NoSuchAlgorithmException nsae) {
        Log.e("AESdemo",
                "no key factory support for PBEWITHSHAANDTWOFISH-CBC");

    } catch (InvalidKeySpecException ikse) {
        Log.e("AESdemo", "invalid key spec for PBEWITHSHAANDTWOFISH-CBC");

    }

    byte[] skAsByteArray = sk.getEncoded();
    skforAES = new SecretKeySpec(skAsByteArray, "AES");

    final String CIPHERMODEPADDING = "AES/CBC/PKCS7Padding";

    byte[] iv = { 0xA, 1, 0xB, 5, 4, 0xF, 7, 9, 0x17, 3, 1, 6, 8, 0xC, 0xD,
            91 };
    IvParameterSpec IV = new IvParameterSpec(iv);

    String decrypted = new String(decrypt(CIPHERMODEPADDING, skforAES, IV, ciphertext));

    return decrypted;

Here's the key: d(*Mu96p@lg91¨%0c*f7&d^`pkçly$f7

The application crashes on the catch block "NoSuchAlgorithmException".

Has anyone experienced this? I have no idea what to do to fix this problem.

Thanks a lot!


Still did not work, Marcus. :/

The error is this:

"Invalid key exception."

See how is my code.

public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    String desc = "starting work...";
    TextView tv1 = (TextView) findViewById(R.id.tv1);
    tv1.setText(desc);

    byte[] KEY_GENERATION_ALG = null;
    try {
        KEY_GENERATION_ALG = ("teste").getBytes("ISO-8859-1");
    } catch (UnsupportedEncodingException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    final int HASH_ITERATIONS = 10000;
    final int KEY_LENGTH= 256;
    SecretKeySpec skforAES=null;
    // Obviously, you must not embed the human-friendly passphrase in your code, as I have done here.
    // The passphrase should be kept outside the mobile device, and the user prompted to enter it.
    // It is supplied as a literal here for convenience of this demonstration
    /*char [] humanPassphrase = {'P','e','r',' ','v','a','l','l','u','m',' ',
                               'd','u','c','e','s',' ','L','a','b','a','n','t' };
    byte [] salt = {0,1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xD,0xE,0xF};  // must save this for next time we want the key


    PBEKeySpec myKeyspec = new PBEKeySpec(humanPassphrase, salt, HASH_ITERATIONS, KEY_LENGTH);
    tv1.setText("PBEKeySpec generated");
    SecretKeyFactory keyfactory=null;
    SecretKey sk=null;
    SecretKeySpec skforAES=null;
    try {
        keyfactory = SecretKeyFactory.getInstance(KEY_GENERATION_ALG);
        sk = keyfactory.generateSecret(myKeyspec);

    } catch (NoSuchAlgorithmException nsae) {
        Log.e("AESdemo", "no key factory support for PBEWITHSHAANDTWOFISH-CBC" );
    } catch (InvalidKeySpecException ikse) {
        Log.e("AESdemo", "invalid key spec for PBEWITHSHAANDTWOFISH-CBC" );
    }

    // This is our secret key.  We could just save this to a file instead of regenerating it
    // each time it is needed.  But that file cannot be on the device (too insecure).  It could
    // be secure if we kept it on a server accessible through https.
    byte[] skAsByteArray = sk.getEncoded();*/
    try {
        skforAES = new SecretKeySpec(KEY_GENERATION_ALG, "AES");
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    final String CIPHERMODEPADDING = "AES/CBC/PKCS7Padding";

    // must save the IV for use when we want to decrypt the text
    byte [] iv = {0xA,1,0xB,5,4,0xF,7,9,0x17,3,1,6,8,0xC,0xD,91};   
    IvParameterSpec IV = new IvParameterSpec(iv);
    byte[] plaintext=null;
    try {
        // Obviously in a real use scenario, the plaintext will not be a literal in your app.
        // This plaintext comes from chapter X of "Alice's Adventures in Wonderland" by Lewis Carroll
        // I like the emphasis the author places on clear explanations ...
        plaintext = (
                  "Tis the voice of the Lobster; I heard him declare,\n"
                + "    \"You have baked me too brown, I must sugar my hair.\"\n "
                + "    As a duck with its eyelids, so he with his nose\n"
                + "    Trims his belt and his buttons, and turns out his toes.'\n"
                + "`I should like to have it explained,' said the Mock Turtle.\n"
                + "`She can't explain it,' said the Gryphon hastily. `Go on with the next verse.'\n"
                + "Alice did not dare to disobey, though she felt sure it would all come wrong, "
                + "and she went on in a trembling voice:-- \n"
                + "    `I passed by his garden, and marked, with one eye, \n"
                + "     How the Owl and the Panther were sharing a pie--' \n"
                + "`What is the use of repeating all that stuff,' the Mock Turtle interrupted, "
                + "`if you don't explain it as you go on? It's by far the most confusing thing I ever heard!'"
                ).getBytes("ISO-8859-1");
    } catch (UnsupportedEncodingException uee) {
        Log.e("AESdemo", "no String support for ISO-8859-1" );
    }

    Log.i("AESdemo", "plaintext length =" + plaintext.length );


    byte[] ciphertext = encrypt(CIPHERMODEPADDING, skforAES, IV, plaintext);

    String decrypted = new String( decrypt(CIPHERMODEPADDING, skforAES, IV, ciphertext) );

    tv1.setText(decrypted);
}

//  Use this method if you want to add the padding manually
//  AES deals with messages in blocks of 16 bytes.
//  This method looks at the length of the message, and adds bytes at the end
//  so that the entire message is a multiple of 16 bytes.
//  the padding is a series of bytes, each set to the total bytes added (a number in range 1..16).
byte [] addPadding (byte[] plain) {
    byte plainpad[] = null;
    int shortage  = 16 - (plain.length % 16);
    // if already an exact multiple of 16, need to add another block of 16 bytes
    if (shortage==0) shortage=16;

    // reallocate array bigger to be exact multiple, adding shortage bits.
    plainpad = new byte[ plain.length+shortage ];
    for (int i=0;i< plain.length; i++) {
        plainpad[i]=plain[i];
    }
    for (int i=plain.length;i<plain.length+shortage;i++) {
        plainpad[i]=(byte)shortage;
    }
    return plainpad;
}

//  Use this method if you want to remove the padding manually
// This method removes the padding bytes
byte [] dropPadding (byte[] plainpad) {
    byte plain[] = null;
    int drop  = plainpad[plainpad.length-1];  //last byte gives number of bytes to drop

    // reallocate array smaller, dropping the pad bytes.
    plain = new byte[ plainpad.length - drop ];
    for (int i=0;i< plain.length; i++) {
        plain[i]=plainpad[i];
        plainpad[i]=0;  // don't keep a copy of the decrypt
    }
    return plain;
}


byte [] encrypt(String cmp, SecretKey sk, IvParameterSpec IV, byte[] msg) {
    try {
        Cipher c = Cipher.getInstance(cmp);
        c.init(Cipher.ENCRYPT_MODE, sk, IV);
        return c.doFinal(msg);
    } catch (NoSuchAlgorithmException nsae) {
        Log.e("AESdemo", "no cipher getinstance support for "+cmp );
    } catch (NoSuchPaddingException nspe) {
        Log.e("AESdemo", "no cipher getinstance support for padding " + cmp );
    } catch (InvalidKeyException e) {
        Log.e("AESdemo", "invalid key exception" );
    } catch (InvalidAlgorithmParameterException e) {
        Log.e("AESdemo", "invalid algorithm parameter exception" );
    } catch (IllegalBlockSizeException e) {
        Log.e("AESdemo", "illegal block size exception" );
    } catch (BadPaddingException e) {
        Log.e("AESdemo", "bad padding exception" );
    }
    return null;
}

byte [] decrypt(String cmp, SecretKey sk, IvParameterSpec IV, byte[] ciphertext) {
    try {
        Cipher c = Cipher.getInstance(cmp);
        c.init(Cipher.DECRYPT_MODE, sk, IV);
        return c.doFinal(ciphertext);
    } catch (NoSuchAlgorithmException nsae) {
        Log.e("AESdemo", "no cipher getinstance support for "+cmp );
    } catch (NoSuchPaddingException nspe) {
        Log.e("AESdemo", "no cipher getinstance support for padding " + cmp );
    } catch (InvalidKeyException e) {
        Log.e("AESdemo", "invalid key exception" );
    } catch (InvalidAlgorithmParameterException e) {
        Log.e("AESdemo", "invalid algorithm parameter exception" );
    } catch (IllegalBlockSizeException e) {
        Log.e("AESdemo", "illegal block size exception" );
    } catch (BadPaddingException e) {
        Log.e("AESdemo", "bad padding exception" );
    }
    return null;
}

}

George Stocker
  • 57,289
  • 29
  • 176
  • 237
Taynã Bonaldo
  • 621
  • 9
  • 17

1 Answers1

0

I'm not really following what you're doing here, but it looks like you're not using the APIs correctly. The argument to SecretKeyFactory.getInstance() is supposed to be the name of the key algorithm, not the actual key. And since you already have the key, you shouldn't need to use the SecretKeyFactory to generate one for you.

Try creating instance of SecretKeySpec directly with your key, like this:

skforAES = new SecretKeySpec(KEY.getBytes("utf-8"), "AES");
Marcus Forsell Stahre
  • 3,766
  • 1
  • 17
  • 14
  • Firstly, thank you for your attention! Despite making a lot of sense what you said, continues to break. But now the error was "Invalid key exception." But I am absolutely certain that the key is correct. What can I try? – Taynã Bonaldo Jul 21 '12 at 00:09
  • Marcus, to help you, here is the encryption code of WS: http://stackoverflow.com/questions/11564719/encryption-decryption-using-rijndael-with-key-256bit-on-android – Taynã Bonaldo Jul 21 '12 at 00:15
  • Not sure which encoding your key is - you probably shouldn't store it as a string, but as an array of bytes. Have a try with my updated answer and see if it works better. – Marcus Forsell Stahre Jul 21 '12 at 12:08
  • Hi Marcus. I did what you instructed me and still did not work. I posted the update of my code. Is that correct? Thank you! – Taynã Bonaldo Jul 23 '12 at 00:49
  • Hi Marcus, how are you? I would like to thank you for your instructions. Everything worked correctly. The problem was that I found later, was on IVs. But now everything is solved! Thank you! – Taynã Bonaldo Jul 24 '12 at 12:12