因此我遇到了从基于字符串的密码生成密钥的问题。加密步骤正常,解密步骤一直有效,直到底部列出的错误,使解密的文件损坏。我使用以下函数来执行加密/解密:
public static boolean decryptFileFromUri(Context context, Uri file, String keyphrase) {
try {
File f = new File(getRealPathFromURI(context, file));
FileInputStream fis = new FileInputStream(f);
File ef = new File(f.toString().replace(".epf", ""));
FileOutputStream fos = new FileOutputStream(ef);
Log.d("HIDEMYPICS","Decrypting: " + f.toString());
byte[] rawKey = getRawKey(keyphrase.getBytes("UTF8"));
/*KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(rawKey);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] key = skey.getEncoded();*/
SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
// Wrap the output stream
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
// Write bytes
int b;
byte[] d = new byte[8];
while ((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
// Flush and close streams.
cos.flush();
cos.close();
fis.close();
Log.d("HIDEMYPICS","Decrypted to: " + ef.toString());
return true;
} catch (IOException e){
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return false;
}
public static boolean encryptFileFromUri(Context context, Uri file, String keyphrase) {
try {
File f = new File(getRealPathFromURI(context, file));
FileInputStream fis = new FileInputStream(f);
File ef = new File(f.toString() + ".epf");
FileOutputStream fos = new FileOutputStream(ef);
Log.d("HIDEMYPICS","Encrypting: " + f.toString());
byte[] rawKey = getRawKey(keyphrase.getBytes("UTF8"));
/*KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(rawKey);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] key = skey.getEncoded();*/
SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
// Wrap the output stream
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
// Write bytes
int b;
byte[] d = new byte[8];
while ((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
// Flush and close streams.
cos.flush();
cos.close();
fis.close();
Log.d("HIDEMYPICS","Encrypted to: " + ef.toString());
return true;
} catch (IOException e){
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return false;
}
这里是生成原始密钥的函数:
private static byte[] getRawKey(byte[] seed) throws NoSuchAlgorithmException {
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();
String result = "";
for(int index = 0; index < raw.length; index++) {
result += Integer.toHexString(raw[index]);
// maybe you have to convert your byte to int before this can be done
// (cannot check reight now)
}
Log.d("HIDEMYPICS","Passphrase: " + new String(seed).toString() + " Key: " + result );
return raw;
}
&#34;测试&#34;的输出对于密钥的上述十六进制转储,输入字符串如下:
加密:
04-17 09:01:25.088 18341-18341/com.dcheeseman.hidemypics D/HIDEMYPICS: Encrypting: /storage/emulated/0/Download/bailout_5128280_GIFSoup.com-1.gif
04-17 09:01:25.088 18341-18341/com.dcheeseman.hidemypics D/HIDEMYPICS: Passphrase: test Key: ffffff85affffffe21023ffffffb7ffffffe8ffffffc8214031fffffffa5b29ffffff9affffff80
解密:
04-17 09:01:43.808 18341-18341/com.dcheeseman.hidemypics D/HIDEMYPICS: Decrypting: /storage/emulated/0/Download/bailout_5128280_GIFSoup.com-1.gif.epf
04-17 09:01:43.808 18341-18341/com.dcheeseman.hidemypics D/HIDEMYPICS: Passphrase: test Key: ffffff8331ffffffe2ffffff87ffffffe242dffffffa61cffffffc7ffffffb4ffffffa1d74ffffff9affffff9b
解密和加密都用&#34; test&#34;作为密码而且该函数返回2个不同的密钥,这就是为什么我认为我得到了解密错误,其完整跟踪列在下面:
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: java.io.IOException: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at javax.crypto.CipherOutputStream.close(CipherOutputStream.java:136)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at com.dcheeseman.hidemypics.AESUtils.decryptFileFromUri(AESUtils.java:102)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at com.dcheeseman.hidemypics.HideMyPics.onActivityResult(HideMyPics.java:35)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at android.app.Activity.dispatchActivityResult(Activity.java:6808)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at android.app.ActivityThread.deliverResults(ActivityThread.java:4698)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at android.app.ActivityThread.handleSendResult(ActivityThread.java:4745)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at android.app.ActivityThread.access$1500(ActivityThread.java:197)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1730)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at android.os.Looper.loop(Looper.java:145)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at android.app.ActivityThread.main(ActivityThread.java:6872)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at java.lang.reflect.Method.invoke(Native Method)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at java.lang.reflect.Method.invoke(Method.java:372)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
04-17 09:33:24.158 823-823/com.dcheeseman.hidemypics W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
提前感谢您对此问题的任何帮助!
答案 0 :(得分:0)
您声明:&#34; 2个不同的键&#34;,键必须相同。
通常,您预先共享密钥或密码,如果您使用密码,则使用PBKDF2等功能从中获取密钥。如果使用密码派生,则必须在加密和解密时使用相同的确定性功能。使用的功能必须从每侧的密码生成相同的密钥。由于您使用的是随机生成器,因此派生不是确定性的,这不起作用。
答案 1 :(得分:0)
接受Zaph的建议并交换到PBKDF2,现在有一致的密钥生成。这是任何有趣的人的代码。
public static SecretKey generateKey(Context c, char[] passphraseOrPin) throws NoSuchAlgorithmException, InvalidKeySpecException {
// Number of PBKDF2 hardening rounds to use. Larger values increase
// computation time. You should select a value that causes computation
// to take >100ms.
byte[] salt = Settings.Secure.getString(c.getContentResolver(),
Settings.Secure.ANDROID_ID).getBytes();
final int iterations = 1000;
final int outputKeyLength = 128;
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
Log.d("HIDEMYPICS","Secret Key: " + toHex(secretKey.getEncoded()) );
return secretKey;
}
public static boolean decryptFileFromUri(Context context, Uri file, String keyphrase) {
try {
File f = new File(getRealPathFromURI(context, file));
FileInputStream fis = new FileInputStream(f);
File ef = new File(f.toString().replace(".epf", ""));
FileOutputStream fos = new FileOutputStream(ef);
Log.d("HIDEMYPICS","Decrypting: " + f.toString());
SecretKey key = generateKey(context, keyphrase.toCharArray());
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
// Wrap the output stream
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
// Write bytes
int b;
byte[] d = new byte[8];
while ((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
// Flush and close streams.
cos.flush();
cos.close();
fis.close();
Log.d("HIDEMYPICS","Decrypted to: " + ef.toString());
return true;
} catch (IOException e){
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return false;
}
public static boolean encryptFileFromUri(Context context, Uri file, String keyphrase) {
try {
File f = new File(getRealPathFromURI(context, file));
FileInputStream fis = new FileInputStream(f);
File ef = new File(f.toString() + ".epf");
FileOutputStream fos = new FileOutputStream(ef);
Log.d("HIDEMYPICS","Encrypting: " + f.toString());
SecretKey key = generateKey(context, keyphrase.toCharArray());
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
// Wrap the output stream
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
// Write bytes
int b;
byte[] d = new byte[8];
while ((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
// Flush and close streams.
cos.flush();
cos.close();
fis.close();
Log.d("HIDEMYPICS","Encrypted to: " + ef.toString());
return true;
} catch (IOException e){
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return false;
}
注意:它仍然无法正常工作,因为它在解密过程中损坏了前几个字节,从而导致文件头损坏。如果您想查看结果,我已在此处开始单独提问:CipherOutputStream corrupting headers in Android