无法在android App中解密字符串

2022-01-10 00:00:00 encryption cryptography android java

我正在尝试开发一个可以加密和解密值的 android 应用程序.所以我关注了这个链接在此处输入链接描述

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,那么它总是会生成相同的随机字节流.

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.

但并非所有提供商都如此;其他供应商只是简单地混合种子.换句话说,他们可以使用预先播种的 PRNG 并混合种子.在这种情况下,getRawKey 方法会为加密和解密生成不同的密钥,这将导致解密失败.

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 作为密钥派生函数或 KDF.如果输入是密码,则应使用真正的 KDF,例如 PBKDF2;如果输入是密钥,则应使用 HKDF.PBKDF2 内置于 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.

应该删除该代码段.它是从 Android 代码片段中复制的,但我再也找不到那个网站了.换句话说,它似乎比它可用时更不正常.

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 加密时检索数据的一种可能解决方案是在 Oracle 提供的 JDK 上对其进行解密.否则,您还可以复制 SHA1PRNG 的内部实现类的代码并使用它来解密您的数据.请注意,您确实需要记住 SUN 的来源是 GPL 的;如果你这样做,你需要遵守该许可证.对于较旧的 Android 版本,您可以使用其源代码.我强烈建议以后删除这段可怕的代码,改用 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.

如果您使用的是返回完全随机密钥的实现,那么您就完全不走运了.您的数据已消失,期间.请放心,我们将永远保密.

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.

相关文章