我在 stackoverflow 上发现了一个有趣的代码:在 Android 中使用 AES 加密的最佳实践是什么?
我进行了一些更改以使其正常工作(已删除implements ICrypto
、更改throws CryptoException
为throws Exception
、添加toHex
和toByte
函数并将一些函数更改为静态)
我试图通过这样调用它来加密一个字符串:
String EncryptedText = AdvancedCrypto.encrypt(AdvancedCrypto.getSecretKey("MyPassword", "MySalt"), "TheStringThatIwantEncrypted");
我究竟做错了什么?我正在使用 Eclipse,我的代码没有错误,但是当我在 Android AVD 上运行它时,什么都没有发生。Logcat 会弹出一些奇怪的日志,我不知道它们是什么意思。
这是我从 logcat 得到的:
W/System.err(346): java.lang.Exception: Unable to get secret key
W/System.err(346): at com.example.enc.AdvancedCrypto.getSecretKey(AdvancedCrypto.java:92)
W/System.err(346): at com.example.enc.MainActivity$1.onClick(MainActivity.java:38)
W/System.err(346): at android.view.View.performClick(View.java:2364)
W/System.err(346): at android.view.View.onTouchEvent(View.java:4179)
W/System.err(346): at android.widget.TextView.onTouchEvent(TextView.java:6541)
W/System.err(346): at android.view.View.dispatchTouchEvent(View.java:3709)
W/System.err(346): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
W/System.err(346): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
W/System.err(346): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
W/System.err(346): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
W/System.err(346): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1659)
W/System.err(346): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1107)
W/System.err(346): at android.app.Activity.dispatchTouchEvent(Activity.java:2061)
W/System.err(346): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1643)
W/System.err(346): at android.view.ViewRoot.handleMessage(ViewRoot.java:1691)
W/System.err(346): at android.os.Handler.dispatchMessage(Handler.java:99)
W/System.err(346): at android.os.Looper.loop(Looper.java:123)
W/System.err(346): at android.app.ActivityThread.main(ActivityThread.java:4363)
W/System.err(346): at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err(346): at java.lang.reflect.Method.invoke(Method.java:521)
W/System.err(346): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
W/System.err(346): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
W/System.err(346): at dalvik.system.NativeStart.main(Native Method)
W/System.err(346): Caused by: java.lang.NumberFormatException: unable to parse 'dh' as integer
W/System.err(346): at java.lang.Integer.parse(Integer.java:374)
W/System.err(346): at java.lang.Integer.parseInt(Integer.java:363)
W/System.err(346): at java.lang.Integer.valueOf(Integer.java:688)
W/System.err(346): at com.example.enc.AdvancedCrypto.toByte(AdvancedCrypto.java:32)
W/System.err(346): at com.example.enc.AdvancedCrypto.getSecretKey(AdvancedCrypto.java:86)
W/System.err(346): ... 22 more
我到目前为止的代码是这样的:
public class AdvancedCrypto {
public static final String PROVIDER = "BC";
public static final int SALT_LENGTH = 20;
public static final int IV_LENGTH = 16;
public static final int PBE_ITERATION_COUNT = 100;
private static final String RANDOM_ALGORITHM = "SHA1PRNG";
private static final String HASH_ALGORITHM = "SHA-512";
private static final String PBE_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String SECRET_KEY_ALGORITHM = "AES";
public static byte[] toByte(String hexString) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private final static String HEX = "0123456789ABCDEF";
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
public static String encrypt(SecretKey secret, String cleartext) throws Exception {
try {
byte[] iv = generateIv();
String ivHex = toHex(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
Cipher encryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
encryptionCipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);
byte[] encryptedText = encryptionCipher.doFinal(cleartext.getBytes("UTF-8"));
String encryptedHex = toHex(encryptedText);
return ivHex + encryptedHex;
} catch (Exception e) {
throw new Exception("Unable to encrypt", e);
}
}
public static String decrypt(SecretKey secret, String encrypted) throws Exception {
try {
Cipher decryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
String ivHex = encrypted.substring(0, IV_LENGTH * 2);
String encryptedHex = encrypted.substring(IV_LENGTH * 2);
IvParameterSpec ivspec = new IvParameterSpec(toByte(ivHex));
decryptionCipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
byte[] decryptedText = decryptionCipher.doFinal(toByte(encryptedHex));
String decrypted = new String(decryptedText, "UTF-8");
return decrypted;
} catch (Exception e) {
throw new Exception("Unable to decrypt", e);
}
}
public static SecretKey getSecretKey(String password, String salt) throws Exception {
try {
PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), toByte(salt), PBE_ITERATION_COUNT, 256);
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBE_ALGORITHM, PROVIDER);
SecretKey tmp = factory.generateSecret(pbeKeySpec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), SECRET_KEY_ALGORITHM);
return secret;
} catch (Exception e) {
throw new Exception("Unable to get secret key", e);
}
}
public String getHash(String password, String salt) throws Exception {
try {
String input = password + salt;
MessageDigest md = MessageDigest.getInstance(HASH_ALGORITHM, PROVIDER);
byte[] out = md.digest(input.getBytes("UTF-8"));
return toHex(out);
} catch (Exception e) {
throw new Exception("Unable to get hash", e);
}
}
public String generateSalt() throws Exception {
try {
SecureRandom random = SecureRandom.getInstance(RANDOM_ALGORITHM);
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt);
String saltHex = toHex(salt);
return saltHex;
} catch (Exception e) {
throw new Exception("Unable to generate salt", e);
}
}
private static byte[] generateIv() throws NoSuchAlgorithmException, NoSuchProviderException {
SecureRandom random = SecureRandom.getInstance(RANDOM_ALGORITHM);
byte[] iv = new byte[IV_LENGTH];
random.nextBytes(iv);
return iv;
}
}