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();
}