Saving encrypted files

Posted on

Problem

public class Encrypt extends Activity {
    EditText Filename;
    EditText secretKey;
    EditText msgContent;
    Button save;
    Button cancel;

    public String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Encrypted Files";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.encrypt);
        Filename = (EditText)  findViewById(R.id.Filename);
        secretKey = (EditText) findViewById(R.id.secretKey);
        msgContent = (EditText)findViewById(R.id.msgContent);
        save = (Button)        findViewById(R.id.save);
        cancel = (Button)      findViewById(R.id.cancel);


        File dir = new File(path);
        dir.mkdir();

        //finish the encrypt activity when you click Cancel button
        cancel.setOnClickListener(new View.OnClickListener(){

            public void onClick(View v) {
                finish();
                                        }
                });
        save.setOnClickListener(new View.OnClickListener() {

                                    @Override
                                    public void onClick(View v) {
                                        String FilenameString = Filename.getText().toString();
                                        String secretKeyString = secretKey.getText().toString();
                                        String msgContentString = msgContent.getText().toString();





                                        // check the validity of the users input
                                        // key length should be 16 characters as defined by AES-128-bit

                                        if (FilenameString.length() > 0 && secretKeyString.length() > 0
                                                && msgContentString.length() > 0 && secretKeyString.length() == 16) {

                                            File file = new File(path + R.id.Filename);
                                            //encryption proccess

                                            byte[] encryptedMsg = encryptMsg(secretKeyString,
                                                    msgContentString);

                                            //convert the byte array to hex format in order for transmission
                                            String[] msgString = byte2hex(encryptedMsg).split(System.getProperty("line.separator"));
                                            //save the message
                                            Toast.makeText(getApplicationContext(), "Saved", Toast.LENGTH_LONG).show();

                                            Save(file, msgString);

                                            finish();

                                        } else
                                            Toast.makeText(
                                                    getBaseContext(),
                                                    "Please enter file name" +
                                                            ", secret key and the message. Secret key must be 16 characters!",

                                                    Toast.LENGTH_LONG).show();

                                    }
                                }
        );
    }

    public static String byte2hex(byte[] b) {
        String hs = "";
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0xFF);
            if (stmp.length() == 1)
                hs += ("0" + stmp);
            else
                hs += stmp;
        }
        return hs.toUpperCase();
    }




    public static byte[] encryptMsg(String secretKeyString, String msgContentString)  {
        try {
            byte[] returnArray;
            //generate AES secret key from users input
            Key key = generateKey(secretKeyString);
            //specify the cipher algorithm using AES
            Cipher c = Cipher.getInstance("AES");
            // specify the encryption mode
            c.init(Cipher.ENCRYPT_MODE, key);
            // encrypt

            returnArray = c.doFinal(msgContentString.getBytes());
            return returnArray;

        }
        catch (Exception e)
        {
            e.printStackTrace();

            byte[] returnArray = null;

            return returnArray;
        }
    }

    private static Key generateKey(String secretKeyString) throws Exception {
        // generate secret key from string

        Key key = new SecretKeySpec(secretKeyString.getBytes(), "AES");
        return key;
    }



    public static void Save(File file, String[] data) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
            try {
                for (int i = 0; i < data.length; i++) {
                    fos.write(data[i].getBytes());
                    if (i < data.length - 1) {
                        fos.write("n".getBytes());
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Solution

I would avoid use of String with such sensitive information, String secretKeyString

These String data values are not explicitly removed; imagine an application reading all these un-encrypted String values stored in the heap. Could use StringBuilder instead and quickly delete the sensitive keys, information as soon as finished using it. Explore password, sensitive data objects to see if there any more classes available which do not store information as immutable String.

Even if there are String instances generated by other objects beyond your control, at least they wouldn’t have such identifying variable labels, secretKeyString.

For your byte2hex you should use a StringBuilder:

public static String byte2hex(byte[] b) {
    //we know exactly how long the resulting string should be so pass that information along to minimize allocations
    StringBuilder hs = new StringBuilder(b.length*2);
    for (int n = 0; n < b.length; n++) {
        String stmp = Integer.toHexString(b[n] & 0xFF);
        if (stmp.length() == 1)
            hs.append("0").append(stmp);
        else
            hs.append(stmp);
    }
    return hs.toString().toUpperCase();
}

Leave a Reply

Your email address will not be published. Required fields are marked *