問題描述
我正在嘗試開發(fā)一個可以加密和解密值的 android 應(yīng)用程序.所以我關(guān)注了這個鏈接在此處輸入鏈接描述
I was trying to develop an android application that could encrypt and decrypt values. So I have followed this link enter link description here
到目前為止,我能夠加密文本,但無法解密它.在我的代碼中,我使用了提供的鏈接中提到的相同的 AESHelper 類.
So far I was able to encrypt a text but I was not able to decrypt it. In my code I have used the same AESHelper class which is mentioned in the link provided.
以下是我用來加密和解密值的活動類
The below is my activity class that i have used to Encrypt and decrypt the values
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity {
EditText text ;
TextView encp,decriptom;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (EditText) findViewById(R.id.editText);
encp = (TextView) findViewById(R.id.valueexcript);
decriptom = (TextView) findViewById(R.id.deexcript);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void Ecript(View v)
{
String Key = "avc";
try {
String normalTextEnc = AHShelper.encrypt(Key, text.getText().toString());
Toast.makeText(this,normalTextEnc,Toast.LENGTH_LONG).show();
encp.setText(normalTextEnc);
} catch (Exception e) {
e.printStackTrace();
}
// Toast.makeText(this,"Hello",Toast.LENGTH_LONG).show();
String decript;
try {
decript = AHShelper.decrypt(Key,encp.getText().toString());
decriptom.setText(decript);
Toast.makeText(this,decript,Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
我用過的AHShelper類如下
AHShelper class that i have used is below
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class AHShelper {
public static String encrypt(String seed, String cleartext)
throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted)
throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
private static byte[] getRawKey(byte[] seed) throws Exception {
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();
return raw;
}
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private static byte[] decrypt(byte[] raw, byte[] encrypted)
throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
public static String toHex(String txt) {
return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
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));
}
}
推薦答案
基本上,這段代碼依賴于一個小技巧:如果你在使用之前為 SUN 提供者和 Bouncy Castle 提供者播種 SHA1PRNG,那么它總是會生成相同的隨機(jī)字節(jié)流.
Basically this code relies on a little trick: if you seed the SHA1PRNG for the SUN provider and Bouncy Castle provider before it is used then it will always generate the same stream of random bytes.
但并非所有提供商都如此;其他供應(yīng)商只是簡單地混合種子.換句話說,他們可以使用預(yù)先播種的 PRNG 并混合種子.在這種情況下,getRawKey
方法會為加密和解密生成不同的密鑰,這將導(dǎo)致解密失敗.
This is not always the case for every provider though; other providers simply mix in the seed. In other words, they may use a pre-seeded PRNG and mix-in the seed instead. In that case the getRawKey
method generates different keys for the encrypt and decrypt, which will result in a failure to decrypt.
也可能是提供商決定完全使用基于 SHA-1 的不同算法,因為 SUN/Oracle 使用的算法沒有很好地指定 - 至少是公開的.
It could also be the case that a provider decides to use a different algorithm based on SHA-1 altogether, as the algorithm used by SUN/Oracle is not well specified - publicly at least.
基本上,這個可怕的代碼片段濫用 SHA1PRNG 作為密鑰派生函數(shù)或 KDF.如果輸入是密碼,則應(yīng)使用真正的 KDF,例如 PBKDF2;如果輸入是密鑰,則應(yīng)使用 HKDF.PBKDF2 內(nèi)置于 Java 中.
Basically this horrible code snippet abuses the SHA1PRNG as a Key Derivation Function or KDF. You should use a true KDF such as PBKDF2 if the input is a password or HKDF if the input is a key. PBKDF2 is build into Java.
應(yīng)該刪除該代碼段.它是從 Android 代碼片段中復(fù)制的,但我再也找不到那個網(wǎng)站了.換句話說,它似乎比它可用時更不正常.
That code snippet should be removed. It has been copied from Android snippets, but I cannot find that site anymore. It seems even more dysfunctional then when it was available in other words.
在使用 SUN 加密時檢索數(shù)據(jù)的一種可能解決方案是在 Oracle 提供的 JDK 上對其進(jìn)行解密.否則,您還可以復(fù)制 SHA1PRNG 的內(nèi)部實現(xiàn)類的代碼并使用它來解密您的數(shù)據(jù).請注意,您確實需要記住 SUN 的來源是 GPL 的;如果你這樣做,你需要遵守該許可證.對于較舊的 Android 版本,您可以使用其源代碼.我強(qiáng)烈建議以后刪除這段可怕的代碼,改用 PBKDF2.
A possible solution to retrieve your data when encrypted with SUN is either to decrypt it on an Oracle provided JDK. Otherwise you could also copy the code of the inner implementation class of the SHA1PRNG and use that to decrypt your data. Note that you do need to keep in mind that the sources of SUN are GPL'ed; you need to adhere to that license if you do. For older Android versions you can use the source code of that. I would strongly advice to remove this horrible piece of code afterwards and rely on PBKDF2 instead.
如果您使用的是返回完全隨機(jī)密鑰的實現(xiàn),那么您就完全不走運了.您的數(shù)據(jù)已消失,期間.請放心,我們將永遠(yuǎn)保密.
If you're using an implementation that returns a fully random key then you're completely out of luck. Your data is gone, period. Rest assured that it will be kept confidential to the end of times.
這篇關(guān)于無法在android App中解密字符串的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!