在尝试访问动态数据时出现空对象引用 – Android Studio

huangapple go评论77阅读模式
英文:

Getting Null Object Reference when Trying to Access Dynamic Data - Android Studio

问题

我正在使用它来解密密码所述密码在URI中在另一个类中)。如果我硬编码密钥它可以工作我正在尝试一种动态方法由于我缺乏经验这就是我遇到困难的地方我无法使这两个类一起工作

```java
public class Decrypt {

    public void myMethod(Context context) {
        try {
            context.getContentResolver().openInputStream(targURI);
        } catch (FileNotFoundException e1) {
            Toast.makeText(context.getApplicationContext(), "无法读取内容。请检查URI是否正确", Toast.LENGTH_LONG).show();
            return;
        }
        BufferedReader reader1 = new BufferedReader(new InputStreamReader(content));
        StringBuffer buffer = new StringBuffer();
        try {
            while ((line = reader1.readLine()) != null) {
                md5key = md5key + line;
            }
            index = md5key.indexOf("MD5_PIN");
            md5key = md5key.substring(index + 10, index + 42);
            Log.i("Test:  ", md5key);
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }

    public String encryppass(String pass) {
        return this.decrypt(pass);
    }

    private String decrypt(String paramString) {
        byte[] arrayOfByte = Base64.decode(paramString.getBytes(), 0);
        try {
            this.cipher = Cipher.getInstance("AES");
            this.cipher.init(2, this.keySpec);
            String str = new String(this.cipher.doFinal(arrayOfByte), "UTF-8");
            return str;
        } catch (Exception exception) {
            exception.printStackTrace();
            return null;
        }
    }
}

MainActivity:

@Override
public void onClick(View view) {

    switch (view.getId()) {

        case R.id.exploit1:
            String[] arrayOfString = {"name", "pwd"};
            Cursor cursor = getContentResolver().query(
                    Uri.parse(PWDMANAGER_URI), arrayOfString, null, null, null);

            Decrypt pp = new Decrypt();
            try {
                if (cursor.moveToFirst()) {
                    do {
                        String name = cursor.getString(0);
                        String encrypted = cursor.getString(1);
                        String decrypted1 = pp.encryppass(encrypted);
                        Log.i("Title:     ", name);
                        Log.i("Password:  ", decrypted1);
                    } while (cursor.moveToNext());
                }
            } catch (NullPointerException exception) {
                exception.printStackTrace();
            }

如何使这些类一起工作的建议?


<details>
<summary>英文:</summary>
I&#39;m using it to decrypt a password (said password is in a URI is in another class).  If I hardcode the key, it works.  I&#39;m trying a dynamic approach, and this is where I struggle due to my lack of experience.  I&#39;m not able to get the two classes to work together.

public class Decrypt {

public void myMethod(Context context) {
try {
context.getContentResolver().openInputStream(targURI);
} catch (FileNotFoundException e1) {
Toast.makeText(context.getApplicationContext(), &quot;Could not read the content. Please check the URI is correct&quot;, Toast.LENGTH_LONG).show();
return;
}
BufferedReader reader1 = new BufferedReader(new InputStreamReader(content));
StringBuffer buffer = new StringBuffer();
try {
while ((line = reader1.readLine()) != null) {
md5key = md5key + line;
}
index = md5key.indexOf(&quot;\&quot;MD5_PIN\&quot;&quot;);
md5key = md5key.substring(index + 10, index + 42);
Log.i(&quot;Test:  &quot;, md5key);
} catch (IOException e1) {
e1.printStackTrace();
}
}

//Decrypts password
public String encryppass(String pass) {
return this.decrypt(pass);
}

private String decrypt(String paramString) {
byte[] arrayOfByte = Base64.decode(paramString.getBytes(), 0);
try {
this.cipher = Cipher.getInstance(&quot;AES&quot;);
this.cipher.init(2, this.keySpec);
String str = new String(this.cipher.doFinal(arrayOfByte), &quot;UTF-8&quot;);
return str;
}
catch (Exception exception) {
exception.printStackTrace();
return null;
}
}

}


MainActivity:
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.exploit1:
String[] arrayOfString = {&quot;name&quot;, &quot;pwd&quot;};
Cursor cursor = getContentResolver().query(
Uri.parse(PWDMANAGER_URI), arrayOfString, null, null, null);
Decrypt pp = new Decrypt();
try {
if (cursor.moveToFirst()) {
do {
String name = cursor.getString(0);
String encrypted = cursor.getString(1);
String decrypted1 = pp.encryppass(encrypted);
Log.i(&quot;Title:     &quot;, name);
Log.i(&quot;Password:  &quot;, decrypted1);
} while (cursor.moveToNext());
}
} catch (NullPointerException exception) {
exception.printStackTrace();
}

Any suggestions on how to get these classes working together?
</details>
# 答案1
**得分**: 1
你所遇到的是由于 `SecretKeySpec` 构造函数引发的 `IllegalArgumentException`,具体出现在以下代码行:
```java
SecretKeySpec keySpec = new SecretKeySpec(this.md5key.getBytes(), "AES");

文档中可以找到,此异常被抛出

“如果算法为空或密钥为空或为空”。

在Java中,String md5key = ""; 表示一个空字符串,因此在传递给 SecretKeySpec 构造函数时会引发此异常。为了解决这个问题,在 md5key 获得正确值之后初始化你的 SecretKeySpec。具体来说,将那行代码改为:

SecretKeySpec keySpec;

并在 Log.i("Test: ", md5key); 所在的位置添加以下代码:

keySpec = new SecretKeySpec(this.md5key.getBytes(), "AES");

MainActivity:

在这行代码调用 encryppass() 之前:

String decrypted1 = pp.encryppass(encrypted);

你需要运行 myMethod() 来从 xml 文件中获取 md5key 的值。只需在上述提到的行之前添加以下代码:

pp.myMethod(this);

在这种情况下,this 指的是 MainActivity,是 Context


以下是几个更多的细微错误(它们不会引起任何错误,但也不是很好的做法,或者是多余的):

  1. 没有必要使用具有完全相同条件的第二个 switch。只需将第二个 case 添加到原始的 switch 中:
switch(view.getId()){
    case R.id.exploit1:
    // exploit 1 的代码
    break; //必须要有,因为 switch 是连续的,因此会继续执行直到找到一个 break。没有它,它还会执行下一个 case(们)

    case R.id.exploit2:
    // exploit 2 的代码
    break;
}
  1. 在你的数据库查询代码中,if(cursor.moveToFirst()) 是多余的。你的方法也是可以的,但你可以更简单地这样做:
while(cursor.moveToNext()){
    String name = cursor.getString(0);
    String encrypted = cursor.getString(1);
    String decrypted1 = pp.encryppass(encrypted);
    Log.i("Title: ", name);
    Log.i("Password: ", decrypted1);
}

第一次调用 cursor.moveToNext() 时,它会移动到第一个位置。因此,在使用游标之前,这个语句需要至少运行一次,所以自然地,这将不适用于 do...while() 语句。

英文:

What you've got is an IllegalArgumentException thrown by the SecretKeySpec constructor, specifically in this line:

SecretKeySpec keySpec = new SecretKeySpec(this.md5key.getBytes(), &quot;AES&quot;);

A bit of digging around in the documentation reveals that this exception is thrown

> "if algorithm is null or key is null or empty".

In Java, String md5key = &quot;&quot;; is an empty String, thus throwing this exception when passed to the SecretKeySpec Constructor. In order to solve it, initialise your SecretKeySpec after md5key has a proper value. More specifically, change that line to:

SecretKeySpec keySpec;

and add this line where Log.i(&quot;Test: &quot;, md5key); is:

keySpec = new SecretKeySpec(this.md5key.getBytes(), &quot;AES&quot;);

MainActivity:

Before calling encryppass() in this line:

String decrypted1 = pp.encryppass(encrypted);

You'll need to run myMethod(), in order to obtain the md5key value from the xml file. Simply add, before the line mentioned above, the follwing:

pp.myMethod(this);

In this case, this is referring to MainActivity, and is the Context.


The following are a few more trivial mistakes (they won't cause any errors, but aren't really in good practice either - or are redundant):

  1. There is no need for a second switch with the exact same condition. Just add a second case to the original switch:

     switch(view.getId()){
    case R.id.exploit1:
    //code for exploit 1
    break; //is necessary, since switch is continuous, therefore, it will continue executing until it finds a break. Without it, it will also execute the next case(s)
    case R.id.exploit2:
    //code for exploit 2
    break;
    }
    
  2. In your database query code, if(cursor.moveToFirst()) is reduntant. The way you did it is also fine, but you could more simply do:

     while(cursor.moveToNext()){
    String name = cursor.getString(0);
    String encrypted = cursor.getString(1);
    String decrypted1 = pp.encryppass(encrypted);
    Log.i(&quot;Title:     &quot;, name);
    Log.i(&quot;Password:  &quot;, decrypted1);
    }
    

    The first time cursor.moveToNext() is called, it will move to the first
    position. Because of this, the statement needs to run at least once before
    the cursor is used so, naturally, this will not work with a do...while() statement.

huangapple
  • 本文由 发表于 2020年9月9日 11:17:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/63804274.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定