I am confused by this bit of advice from http://developer.android.com/guide/google/play/billing/billing_integrate.html#billing-signatures
To keep your public key safe from malicious users and hackers, do not
embed your public key as an entire literal string. Instead, construct
the string at runtime from pieces or use bit manipulation (for
example, XOR with some other string) to hide the actual key. The key
itself is not secret information, but you do not want to make it easy
for a hacker or malicious user to replace the public key with another
key.
Does this mean that
String one = "thisIs";
String two = "MyKey";
String base64EncodedPublicKey = one + two;
PublicKey key = Security.generatePublicKey(base64EncodedPublicKey);
verified = Security.verify(key, signedData, signature);
is safer than
String base64EncodedPublicKey = "thisIsMyKey";
PublicKey key = Security.generatePublicKey(base64EncodedPublicKey);
verified = Security.verify(key, signedData, signature);
? If not, could you please give me an example in code of how to do this?
Something that involves some serious change of the key is best. Personally, I prefer using encryption, something like this would work. For the key, string together a few parts, and it should help to getting it together. Use encryptKey to get your key encrypted, then delete the real key from the source code, and you should be fairly secure. Better is to somehow get the key from a secure server, but that isn't always an option.
String encryptKey(String input)
{
byte[] inBytes=input.getBytes();
String finalString=null;
try {
Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] keyBytes=md.digest((KeyPart1+KeyPart2).getBytes());
keyBytes = Arrays.copyOf(keyBytes, 16);
SecretKey key= new SecretKeySpec(keyBytes,"AES");
IvParameterSpec ivSpec = new IvParameterSpec(new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
cipher.init(Cipher.ENCRYPT_MODE,key,ivSpec);
byte[] outBytes = new byte[cipher.getOutputSize(inBytes.length)];
//cipher.update(encrypted, 0, encrypted.length, decrypted, 0);
outBytes=cipher.doFinal(inBytes);
finalString=new String(Base64.encode(outBytes,0));
Log.v(TAG,"Encrypted="+finalString);
} catch (NoSuchAlgorithmException e) {
Log.e(TAG,"No Such Algorithm",e);
} catch (NoSuchPaddingException e) {
Log.e(TAG,"No Such Padding",e);
} catch (InvalidKeyException e) {
Log.e(TAG,"Invalid Key",e);
} catch (InvalidAlgorithmParameterException e) {
Log.e(TAG,"Invalid Algorithm Parameter",e);
} catch (IllegalBlockSizeException e) {
} catch (BadPaddingException e) {}
return finalString;
}
String decryptKey(String base64Text)
{
byte[] encrypted=Base64.decode(base64Text,0);
//encrypted=base64Text.getBytes();
String decryptedString=null;
try {
Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] keyBytes=md.digest((KeyPart1+KeyPart2).getBytes());
keyBytes = Arrays.copyOf(keyBytes, 16);
SecretKey key= new SecretKeySpec(keyBytes,"AES");
IvParameterSpec ivSpec = new IvParameterSpec(new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
cipher.init(Cipher.DECRYPT_MODE,key,ivSpec);
byte[] decrypted = new byte[cipher.getOutputSize(encrypted.length)];
//cipher.update(encrypted, 0, encrypted.length, decrypted, 0);
decrypted=cipher.doFinal(encrypted);
decryptedString=new String(decrypted);
} catch (NoSuchAlgorithmException e) {
logStackTrace(e);
} catch (NoSuchPaddingException e) {
logStackTrace(e);
} catch (InvalidKeyException e) {
logStackTrace(e);
} catch (InvalidAlgorithmParameterException e) {
logStackTrace(e);
} catch (IllegalBlockSizeException e) {
logStackTrace(e);
} catch (BadPaddingException e) {
logStackTrace(e);
}
return decryptedString;
}
Yes. Although in this case you're just concatenating strings which is not much better. The reason for this is that somebody could easily disassemble your code and access your public key. If you have to reassemble the key, it makes it much more challenging to grab the key out of the disassembled code.
Related
I am new in Text file Encryption in Android. And tried so many example of text encryption but i am so confused how to apply.
I have 5 string records from json response and i want to save them in a text file(in External Storage) and in "Encrypted format" . I've tried code of cipher_text_encoding but really confused with lots of classes in it.
Please suggest me either good tutorial for text encryption or give me hint how to encode.
Thanks in advance.
Encryption and Decryption using AES Secret Key Algorithm
Generate AES Secret Key:
public static byte[] generateAesSecretKey(){
String SALT2 = "strong_salt_value";
String username = "user_name";
String password = "strong_password";
byte[] key = (SALT2 + username + password).getBytes();
SecretKey secretKeySpec = null;
try {
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
secretKeySpec = new SecretKeySpec(key, "AES");
} catch (Exception e) {
e.printStackTrace();
}
return secretKeySpec.getEncoded();
}
Encryption:
public static byte[] encodeFile(byte[] secretKey, byte[] fileData) {
SecretKeySpec skeySpec = new SecretKeySpec(secretKey, "AES");
byte[] encrypted = null;
try {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
encrypted = cipher.doFinal(fileData);
// Now write your logic to save encrypted data to sdcard here
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
return encrypted;
}
Decryption:
public static byte[] decodeFile(byte[] key, byte[] fileData) {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
byte[] decrypted = null;
try {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
decrypted = cipher.doFinal(fileData);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalBlockSizeException | BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch(Exception e){
// for all other exception
e.printStackTrace();
}
return decrypted;
}
Hope above methods are useful for you!
AS with every beginner it is normal to get confused, instead of do it yourself everything learn to leverage on code reuse or written shared libraries. This will leverage on code abstraction as you are only interested in say Encryption and Decryption of JSON/Sting.
For a Full Document:
https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html
For a reusable (Java/Android) library:
https://github.com/alkathirikhalid/security
Simple Usage:
String plainText = "Your String";
String encryptionKey = "Your Encryption Key";
String IV = "Your Initial Vector";
// To Encrypt
String cipherText = AES.encrypt(plainText, encryptionKey, IV);
// To Decrypt returned value same as plainText
String originalText = AES.decrypt(cipherText, encryptionKey, IV);
Cheers.
I have to implement encryption in android app. The web developer is using CryptoJs library. means Encryption alog is AES256 encryption.
Both iOS and android platforms give different strings and iOS one is accepted at web.It should be same for sample strings.
I am using below code snippets (there are 2 different diffrent functions):
private void newEnc() {
String secret = "LSC#SD2017#ps";
String cipherText = "{\"device_type\":\"iOS\",\"email\" : \"jhon#gmail.com\",\"device_id\" : \"14105DA4-CEE5-431E-96A2-2331CDA7F062\",\"password\" : \"123456\",\"device_token\" : \"B44777563552882EC3139A0317E401B55D6FC699D0AC3D279F392927CAF9B566\"}";
KeyGenerator kgen = null;
try {
kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(secret.getBytes("UTF8"));
kgen.init(256, sr);
SecretKey skey = kgen.generateKey();
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec skeySpec = new SecretKeySpec(skey.getEncoded(), "AES");
c.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] decrypted = c.doFinal(cipherText.getBytes());
System.out.println(Base64.encodeToString(decrypted, Base64.NO_WRAP));
// decrypted = Base64.encodeBase64(decrypted);
// byte[] iv = Base64.encodeBase64(c.getIV());
// Log.e("encryptString", new String(decrypted));
// Log.d("encryptString iv", new String(iv));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
}
I also used :
private void enctest(String cipherText) {
String secret = "LSC#SD2017#ps";
// String cipherText = "{\"device_type\":\"iOS\",\"email\" : \"jhon#gmail.com\",\"device_id\" : \"14105DA4-CEE5-431E-96A2-2331CDA7F062\",\"password\" : \"123456\",\"device_token\" : \"B44777563552882EC3139A0317E401B55D6FC699D0AC3D279F392927CAF9B566\"}";
MessageDigest md5 = null;
try {
// String cipherText = "U2FsdGVkX1+tsmZvCEFa/iGeSA0K7gvgs9KXeZKwbCDNCs2zPo+BXjvKYLrJutMK+hxTwl/hyaQLOaD7LLIRo2I5fyeRMPnroo6k8N9uwKk=";
byte[] cipherData = Base64.decode(cipherText.getBytes(), Base64.NO_WRAP);
byte[] saltData = Arrays.copyOfRange(cipherData, 8, 16);
md5 = MessageDigest.getInstance("MD5");
final byte[][] keyAndIV = GenerateKeyAndIV(32, 16, 1, saltData, secret.getBytes("UTF-8"), md5);
SecretKeySpec key = new SecretKeySpec(keyAndIV[0], "AES");
IvParameterSpec iv = new IvParameterSpec(keyAndIV[1]);
byte[] encrypted = Arrays.copyOfRange(cipherData, 16, cipherData.length);
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCBC.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] decryptedData = aesCBC.doFinal(cipherText.getBytes("UTF-8"));
// String plainText = "Hello, World! This is a Java/Javascript AES test.";
// SecretKey key = new SecretKeySpec(
// Base64.decodeBase64("u/Gu5posvwDsXUnV5Zaq4g=="), "AES");
// AlgorithmParameterSpec iv = new IvParameterSpec(
// Base64.decodeBase64("5D9r9ZVzEYYgha93/aUK2w=="));
// Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// cipher.init(Cipher.ENCRYPT_MODE, key, iv);
// System.out.println(Base64.encodeBase64String(cipher.doFinal(
// plainText.getBytes("UTF-8"))));
// String decryptedText = new String(decryptedData, "UTF-8");
System.out.println(Base64.encodeToString(decryptedData, Base64.NO_WRAP));
// enctest(decryptedText);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
But none gives the same results.
in iOS they are using https://github.com/etienne-martin/CryptoJS.swift
What should I do that both of our encrypted strings match.
The actual cipherText (not to be confused the character string with the same variable name) is formatted and starts with "Salted__" and presumably encryption parameters. The two different functions create different outputs with different formats. They can not produce the same output.
Note 1, confusing cipherText:
// String cipherText = "{\"device_type\":\"iOS\",\"email\" : \"jhon#gmail.com\",\"device_id\" : \"14105DA4-CEE5-431E-96A2-2331CDA7F062\",\"password\" : \"123456\",\"device_token\" : \"B44777563552882EC3139A0317E401B55D6FC699D0AC3D279F392927CAF9B566\"}";
// String cipherText = "U2FsdGVkX1+tsmZvCEFa/iGeSA0K7gvgs9KXeZKwbCDNCs2zPo+BXjvKYLrJutMK+hxTwl/hyaQLOaD7LLIRo2I5fyeRMPnroo6k8N9uwKk=";
Note 2:
Base64 is so un-useful for humans, it is designed for computers, hex is for humans and computers with a direct bits to bytes correspondence.
I have a settings screen where I want the user to fill personal details.
I want to keep them in sharedpreferences.
I would like to encrypt the data before saving in Sharedpreferences.
Only when it is used, it's in another application activity decrypt what exists in sharedpreferences and use it.
For this purpose I encrypted the information in the settings screen and save the string that was encrypted in to sharedpreferences.
In order to Decrypt I need the same privateKey and I do not know how to move it to the other activity. I tried using sharedpreferences but the program was flying.
Would appreciate help
Code:
try{
SharedPreferences.Editor editor =getActivity().getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit();
afterEncryptCvv = Encrypt((String) newValue,editor);
editor.putString("cvvValue", afterEncryptCvv);
editor.commit();
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
The Encrypt Function:
public static String Encrypt(String plain, SharedPreferences.Editor editor)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
IllegalBlockSizeException, BadPaddingException
{
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
Gson gson4 = new Gson();
String json4 = gson4.toJson(privateKey);
editor.putString("privateKey", json4);
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedBytes = cipher.doFinal(plain.getBytes());
encrypted = bytesToString(encryptedBytes);
return encrypted;
}
In The second activity:
SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE);
try {
Gson gson4 = new Gson();
String json4 = prefs.getString("privateKey", "");
privateKey = gson4.fromJson(json4, PrivateKey.class);
cvvValue = prefs.getString(Cvv, "");
String temp = Decrypt(cvvValue);
cvvValue =temp;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
The Decrypt Function:
public String Decrypt (String result) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
BadPaddingException
{
cipher1= Cipher.getInstance("RSA");
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
decryptedBytes = cipher1.doFinal(stringToBytes(result));
decrypted = new String(decryptedBytes);
return decrypted;
}
You should not store the secret key on the internal storage. Someone with a rooted device can extract it easily.
Instead, after generating the key pair, you can save it in Android Key Store (see here: http://developer.android.com/training/articles/keystore.html) and use it when needed.
For example:
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry entry = ks.getEntry(alias, null);
First of all, I've reviewed all the entries on the forum, and I still can not find a solution to my problem.
I have to measure the time it takes to encode and decode a text with DES, and make a comparison with other algorithms.
When I run the code, I have this error: BadPaddingException: pad block corrupted. When I debug, the code fails in this line:
byte [] plaintext = cipher.doFinal (cipherBytes);
I use class Base64 to encode/decode String <--> byte[]
Any idea?
thanks
private static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";
private static int KEY_LENGTH = 64;
public static SecretKey deriveKeyDES() {
try {
long start = System.currentTimeMillis();
KeyGenerator kgen = KeyGenerator.getInstance("DES");
kgen.init(KEY_LENGTH);
SecretKey result = kgen.generateKey();
long elapsed = System.currentTimeMillis() - start;
return result;
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
public static String encrypt(String plaintext, SecretKey key) {
try {
long start = System.currentTimeMillis();
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding")
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = cipher.doFinal(plaintext.getBytes("UTF-8"));
long elapsed = System.currentTimeMillis() - start;
return toBase64(cipherText);
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
public static String toBase64(byte[] bytes) {
return Base64.encodeToString(bytes, Base64.NO_WRAP).trim();
}
public static String decrypt(String ciphertext, SecretKey key) {
try {
byte[] cipherBytes = fromBase64(ciphertext);
long start = System.currentTimeMillis();
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
cipher.update(cipherBytes);
// This is where I get exception
byte[] plaintext = cipher.doFinal(cipherBytes);
String plainrStr = new String(plaintext, "UTF-8").trim();
long elapsed = System.currentTimeMillis() - start;
return plainrStr;
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
public static byte[] fromBase64(String base64) {
return Base64.decode(base64, Base64.NO_WRAP);
}
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
cipher.update(cipherBytes);
// byte[] plaintext = cipher.doFinal(cipherBytes);
// ^-- You shouldn't pass cipherBytes twice.
// v-- instead use the parameter-less method:
byte[] plaintext = cipher.doFinal();
Padding exception occur when the last cipher text block does not compute to valid plain text. This would happen if last ciphertext block is corrupted or the key is incorrect. For CBC mode it would also happen if the second to last ciphertext was altered (but you are using ECB mode encryption).
In your case, the deriveKeyDES() is always generating a random key. Although we didn't get the actual calls to the security methods, I would presume you use a different key for encryption and decryption. In that case there is a very high chance that the resulting plain text does not contain valid padding bytes.
Rasmus answer certainly points to an error in your code, and it would screw up your timings and return a the plain text two times, but it would not remove the BadPaddingException.
I had the same problem in one source code, and IllegalBlockSizeException in another one.
Solved this two problems by return encoding data like:
public String encrypt(String input) {
try {
byte[] inputBytes = input.getBytes("UTF-8");
byte[] enc = encryptCipher.doFinal(inputBytes);
// and problem was in return encoding. That's how i fixed it
return Base64.encodeToString(enc,Base64.DEFAULT);
.....
}
}
Give u a code for decrypt:
public String decrypt(String input) {
try {
byte[] dec = Base64.decode(input.getBytes(), Base64.DEFAULT);
//here had exception
byte[] utf8 = decryptCipher.doFinal(dec);
return new String(utf8,"UTF8");
} catch (IOException | BadPaddingException | IllegalBlockSizeException e) {
e.printStackTrace();
}
return null;
}
I should submit, that had BadPaddingException and IllegalBlockSizeException
only in decrypt method byte[] utf8 = decryptCipher.doFinal(dec); (u had exeption in the same place: byte[] plaintext = cipher.doFinal(cipherBytes);), but real wrong is in encrypt method(return value)
That's why i recommend u to use that code in encrypt method:
return Base64.encodeToString(enc,Base64.DEFAULT);
P.S Tried to a give full answer on your question.
In my application i want to store some secure data by encrypting it. When the user wants i need to show it to him by decrypting it.
This is working fine.
But the problem is i need to store both encrypted message and initialization vector for every message. This initialization vector is generated while encrypting and i have to use this while decrypting to get the original message.
So if the user stores 1000 messages i need to store those 1000 encrypted messages and corresponding 1000 initialization vectors.I want to avoid storing initialization vector for every message.
Please tell me the way to AES-256 encryption with out Initialization vector.
Below is my code for encrypting and decrypting
/*
* This method will do the AES-256 encryption.
*/
private byte[] encrypt(char[] raw, String cardno) {
// This raw is some unique key like password.
SecretKeyFactory factory = null;
SecretKey tmp = null;
Cipher cipher = null;
byte[] ciphertext = null;
AlgorithmParameters params = null;
try {
factory = SecretKeyFactory.getInstance("PBEWITHSHA-256AND256BITAES-CBC-BC");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
KeySpec spec = new PBEKeySpec(raw, mSalt, 1024, 256);
try {
if (factory != null)
tmp = factory.generateSecret(spec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
if (tmp != null)
mSecret = new SecretKeySpec(tmp.getEncoded(), "AES");
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
try {
if (cipher != null)
cipher.init(Cipher.ENCRYPT_MODE, mSecret);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
if (cipher != null)
params = cipher.getParameters();
try {
mIV = params.getParameterSpec(IvParameterSpec.class).getIV();
} catch (InvalidParameterSpecException e) {
e.printStackTrace();
}
try {
ciphertext = cipher.doFinal(cardno.getBytes("UTF-8"));
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return ciphertext;
}
/*
* This will decrypt the encrypted data based on provided key
*/
private byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
//This raw is initialization vector generated while encrypting
Cipher cipher = null;
byte[] decrypted = null;
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
try {
cipher.init(Cipher.DECRYPT_MODE, mSecret, new IvParameterSpec(raw));
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
try {
decrypted = cipher.doFinal(encrypted);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return decrypted;
}
A better way is to simply add the initialization vector at the start of each encrypted message you save. As the padding already may add some bytes to the message, this should not matter much regarding the use case.
Don't forget, the IV always has a fixed size for a particular block cipher: the block size, which you can retrieve using cipher.getBlockSize() in Java. You can simply use cipher.doFinal(buf, offset, length) instead of cipher.doFinal(buf) after retrieving the IV.
If you really don't want to store the IV, you could calculate the IV from the full path name (the absolute path, or from some root, if needed), and perform a hash such as SHA-256 over it. As long as the path is unique, the SHA-256 should be relatively close to a known but random IV, which is what would be most safe. Of course, if you rename/move the file...
Note that you are trying to safe yourself only about 16KB of initialization vector (1000 x 16, which is the block size). That's not a lot.
To be secure, you must use an initialization vector (and a unique one) for each message. There is no way to get around it.