Android加密和解密文本失败

时间:2015-06-15 18:23:00

标签: android security encryption encryption-symmetric

我尝试加密一些文本(这里是命名代码)并再次解密。 为此,我使用了一个4位数的Pin盐水。

在此之后文本被加密,也是一些Base64解码,所以我可以安全地再次输出字符串。

据我所知,我必须对它进行base64.decode然后再解密它。

但我没有正确解密我的加密文本。只是一些不同的文字。 (像这样[B @ 3ceB ...)

这只是一个小项目,没什么大不了的。它也是我的第二个Android应用程序,所以一些很好的例子会很棒。

String pinstr = new String();
pinstr = "5555";
try {
    EncryptDecrypt encryptor = new EncryptDecrypt(pinstr);
    //encryptor.encrypt(code);
    String encrypted = new String();
    encrypted = encryptor.encrypt(code);

    String decrypted = new String();
    decrypted = encryptor.decrypt(encrypted);

    Toast.makeText(MainActivity.this, decrypted, Toast.LENGTH_SHORT).show();
} catch (InvalidKeyException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (UnsupportedEncodingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (NoSuchPaddingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IllegalBlockSizeException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (BadPaddingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
public class EncryptDecrypt {
    private SecretKeySpec skeySpec;
    private Cipher cipher, cipher2;


    EncryptDecrypt(String password) throws NoSuchAlgorithmException,
    UnsupportedEncodingException, NoSuchPaddingException,
    IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
        MessageDigest sha = MessageDigest.getInstance("SHA-1");
        byte[] key = Arrays.copyOf(sha.digest(("ThisisMySalt1234" + password).getBytes("UTF-8")),
        16);
        skeySpec = new SecretKeySpec(key, "AES");
        cipher = Cipher.getInstance("AES");
        cipher2 = Cipher.getInstance("AES");
    }

    String encrypt(String clear) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
        String encrypted = new String();

        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

        byte[] encryptedBytes = null;
        encryptedBytes = cipher.doFinal(clear.getBytes());

        encrypted = Base64.encodeToString(encryptedBytes, Base64.DEFAULT);

        return encrypted;
    }

    // fehlerhaft
    String decrypt(String encryptedBase64) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        String decrypted = new String();
        cipher2.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] decodedBytes = null;


        decodedBytes = Base64.decode(encryptedBase64, Base64.DEFAULT);

        decrypted = cipher2.doFinal(decodedBytes).toString();

        return decrypted;

    }
}

2 个答案:

答案 0 :(得分:1)

Cipher#doFinal(byte[])的输出类型是byte[],但是数组没有默认的打印内容的方式。通过在数组上调用byte[].toString(),您只需打印其类型和哈希码。 (更多关于此here

你想要的是

decrypted = new String(cipher2.doFinal(decodedBytes), "UTF-8");

告诉String构造函数给定的字节数组包含以UTF-8编码的字符。

当你这样做时,你还需要以特定的编码从字符串中获取字节数组:

clear.getBytes("UTF-8")

如果省略编码,则使用系统默认值,当您在具有不同系统编码默认值的系统上发送密文时,可能会使您的明文无法恢复。

顺便说一句,您不需要两个Cipher个实例。只有一个就足够了,因为你总是在加密和解密过程中启动它。

其他安全问题:

  • 始终使用完全限定的密码字符串。因此,将Cipher.getInstance("AES")更改为Cipher.getInstance("AES/CBC/PKCS5Padding")
  • 使用"AES"密码字符串时,切勿使用默认的ECB模式。它在语义上不安全。至少使用CBC模式和随机IV:

    SecureRandom r = new SecureRandom();
    byte[] iv = new byte[16];
    r.nextBytes(iv);
    ...
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(iv));
    

    IV不应该是秘密的,所以你可以简单地将它添加到密文并在解密前将其拼接。

  • 验证您的密文,以便您不会受到填充oracle攻击,并且可以随时检查您的密文的完整性。这可以通过加密然后MAC方案轻松完成,该方案具有强大的MAC算法,如HMAC-SHA256。您还可以使用经过身份验证的加密模式,如GCM或EAX。

答案 1 :(得分:1)

你的代码有效,但你丢掉了结果。

更改行

decrypted = cipher2.doFinal(decodedBytes).toString();

 decrypted = new String(cipher2.doFinal(decodedBytes),"UTF-8");

然后你得到解码的String而不是字节数组的ID(调用toString()确实把字节数组作为String)。

BTW:您不需要在Java中初始化变量。 String encrypted = new String();没用。只需写下String encrypted;