无法在 Android 中解密加密的短信(在 2.2 操作系统中加密)...(尝试在 2.3 操作系统中解密)

发布于 2024-12-20 09:50:07 字数 3308 浏览 4 评论 0原文

我能够加密短信并将其从一个模拟器(Android 2.2)发送到另一个模拟器。 在接收端我能够成功解密。但问题是,如果在一个操作系统版本(即 Android 2.2)中进行加密并尝试在另一个操作系统版本(Android 2.3)中解密,我会收到“错误填充异常”。我检查了一下两端都使用了相同的密钥。 代码如下所示

public class ED {


    private  String Key;

        public ED() {
            Key = "abc12";   // Assigning default key.
        }

        public ED(String key) {
            // TODO Auto-generated constructor stub
            Key = key;

        }



        public String encrypt(String toEncrypt) throws Exception {
            byte[] rawKey = getRawKey(Key.getBytes("UTF-8"));
            byte[] result = encrypt(rawKey, toEncrypt.getBytes("UTF-8"));
            return toHex(result);
        }



        public  byte[] encrypt(byte[] key, byte[] toEncodeString) throws Exception {

            SecretKeySpec sKeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);

            byte[] encrypted = cipher.doFinal(toEncodeString);

            return encrypted;
        }

        private  byte[] getRawKey(byte[] key) throws Exception {

            KeyGenerator kGen = KeyGenerator.getInstance("AES");
            SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
            sr.setSeed(key);
            kGen.init(128, sr);
            SecretKey sKey = kGen.generateKey();
            byte[] raw = sKey.getEncoded();
            return raw;

        } 

    /************************************* Decription *********************************************/

            public String decrypt(String encryptedString) throws Exception {

                byte[] rawKey = getRawKey(Key.getBytes("UTF-8"));
                System.out.println("Decrypted Key in bytes : "+rawKey);


                System.out.println("Key in decryption :"+rawKey);


                SecretKeySpec sKeySpec = new SecretKeySpec(rawKey, "AES");
                Cipher cipher = Cipher.getInstance("AES");
                cipher.init(Cipher.DECRYPT_MODE, sKeySpec);
                byte[] decrypted = cipher.doFinal(toByte(encryptedString));
                System.out.println("Decrypted mess in bytes---------->" +decrypted);
                return new String(decrypted);
            }






            public 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 String HEX = "0123456789ABCDEF";
            private void appendHex(StringBuffer sb, byte b) {
                sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
            }

            public 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;
            }

    }

,我正在使用 sendTextMessage() 函数发送短信。我读到加密/解密不依赖于操作系统,但在这种情况下事实并非如此。配置密码(在 AES 中)时我是否遗漏了任何重要的事情?请告诉我。

I am able to encrypt an SMS and send it from one simulator (Android 2.2) to another.
On the receiving end I am able to do the decryption successfully. But the problem is if do the encryption in one OS version (i.e Android 2.2) and trying to decrypt in another OS version ( Android 2.3 ) i am getting 'Bad padding exception'. I checked that i used the same key on both ends.
The code is shown below

public class ED {


    private  String Key;

        public ED() {
            Key = "abc12";   // Assigning default key.
        }

        public ED(String key) {
            // TODO Auto-generated constructor stub
            Key = key;

        }



        public String encrypt(String toEncrypt) throws Exception {
            byte[] rawKey = getRawKey(Key.getBytes("UTF-8"));
            byte[] result = encrypt(rawKey, toEncrypt.getBytes("UTF-8"));
            return toHex(result);
        }



        public  byte[] encrypt(byte[] key, byte[] toEncodeString) throws Exception {

            SecretKeySpec sKeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);

            byte[] encrypted = cipher.doFinal(toEncodeString);

            return encrypted;
        }

        private  byte[] getRawKey(byte[] key) throws Exception {

            KeyGenerator kGen = KeyGenerator.getInstance("AES");
            SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
            sr.setSeed(key);
            kGen.init(128, sr);
            SecretKey sKey = kGen.generateKey();
            byte[] raw = sKey.getEncoded();
            return raw;

        } 

    /************************************* Decription *********************************************/

            public String decrypt(String encryptedString) throws Exception {

                byte[] rawKey = getRawKey(Key.getBytes("UTF-8"));
                System.out.println("Decrypted Key in bytes : "+rawKey);


                System.out.println("Key in decryption :"+rawKey);


                SecretKeySpec sKeySpec = new SecretKeySpec(rawKey, "AES");
                Cipher cipher = Cipher.getInstance("AES");
                cipher.init(Cipher.DECRYPT_MODE, sKeySpec);
                byte[] decrypted = cipher.doFinal(toByte(encryptedString));
                System.out.println("Decrypted mess in bytes---------->" +decrypted);
                return new String(decrypted);
            }






            public 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 String HEX = "0123456789ABCDEF";
            private void appendHex(StringBuffer sb, byte b) {
                sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
            }

            public 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;
            }

    }

And I am using sendTextMessage() function to send an sms. I read that encryption/decryption doesn't depend on OS but in this case that is not true. Am I missing any important things while configuring the Cipher (in AES) ? Please let me know.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

皓月长歌 2024-12-27 09:50:07

这是setSeed()。它不会做你认为它会做的事情:它只是将给定种子的熵添加到底层算法中。您可能会发现它在两个平台上返回不同的内容。 SHA1PRNG一个伪随机函数,但如果它已经被播种,它可能会返回不同的结果。

It's setSeed(). It does not do what you think it does: it just adds the entropy of the given seed to the underlying algorithm. You'll probably find out that it returns somehthing different on both platforms. SHA1PRNG is a pseudo random function, but if it is already seeded, it's likely to return different results.

仙气飘飘 2024-12-27 09:50:07

如果问题出在密钥长度上,您可以从密码中派生密钥,而不是直接使用它。您可以使用哈希(如 SHA-1、MD5 等)并将其裁剪为正确的大小(128、192 或 256 位),或使用 PBEKeySpec 而不是 SecretKeySpec

这是为了消除密钥长度的问题。如果填充问题是在明文中,我建议您使用CipherInputStreamCipherOutputStream,它们比Cipher.doFinal更适合程序员使用>。

If the problem is in the key length, you could derivate a key from your password, instead of using it directly. You could use a Hash (like SHA-1, MD5, etc) and crop it to the correct size (128, 192 or 256 bits), or use PBEKeySpec instead of SecretKeySpec.

That to remove problems with the key length. If the padding problems were in the plaintext, I suggest you to use CipherInputStream and CipherOutputStream, which are more programmer-friendly to use than Cipher.doFinal.

梦初启 2024-12-27 09:50:07

不要仅仅因为以相同的方式播种 RNG,就依赖 KeyGenerator 生成相同的密钥。如果您要预先共享密钥,请共享密钥,而不是种子。

您还应该完全指定加密转换:“AES/ECB/PKCS5Padding”

最后,ECB 模式对于一般用途来说并不安全。

有关使用 JCE 正确执行加密的示例,请参阅我的另一个答案

Don't rely on KeyGenerator to generate the same key just because you seeded the RNG the same way. If you are pre-sharing a key, share the key, not the seed.

You should also specify the encryption transform completely: "AES/ECB/PKCS5Padding"

Finally, ECB mode is not secure for general use.

See another answer of mine for an example to perform encryption correctly with the JCE.

画▽骨i 2024-12-27 09:50:07

问题在于 SecureRandom 生成。它在不同的平台上给出不同的结果。这是因为在 engineNextBytes() 方法中 SHA1PRNG_SecureRandomImpl.java 第 320 行(在 Gingerbread 源代码中)上的错误修复

bits = seedLength << 3 + 64; 

已更改为

bits = (seedLength << 3) + 64; 

使用 SecretKeyFactory() 生成安全密钥而不是安全随机。

public class Crypto {

Cipher ecipher;
Cipher dcipher;

byte[] salt = { 1, 2, 4, 5, 7, 8, 3, 6 };
int iterationCount = 1979;

Crypto(String passPhase) {
    try {
        // Create the key
        KeySpec keySpec = new PBEKeySpec(passPhase.toCharArray(), salt, iterationCount);
        SecretKey key = SecretKeyFactory.getInstance("PBEWITHSHA256AND128BITAES-CBC-BC").generateSecret(keySpec);
        ecipher = Cipher.getInstance(key.getAlgorithm()); 
        dcipher = Cipher.getInstance(key.getAlgorithm());

        AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);

        ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
        dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

    } catch (Exception e) {
        // TODO: handle exception
        //Toast.makeText(this, "I cought ", Toast.LENGTH_LONG).show();
    }


}

public String encrypt(String str) {
    String rVal;
    try {
        byte[] utf8 = str.getBytes("UTF8");

        byte[] enc = ecipher.doFinal(utf8);

        rVal = toHex(enc);

    } catch (Exception e) {
        // TODO: handle exception
        rVal = "Exception Caught "+e.getMessage();
    }
    return rVal;
}


public String decrypt(String str) {
    String rVal;
    try {
        byte[] dec = toByte(str);
        byte[] utf8 = dcipher.doFinal(dec);

        rVal = new String(utf8, "UTF8");

    } catch(Exception e) {
        rVal = "Error in decrypting :"+e.getMessage();
    }
    return rVal;
}

private 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;
}
private 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));
}


}

The problem is with SecureRandom generation. It is giving different results on different platforms. It's because of a bug fix on line 320 (in Gingerbread source) of SHA1PRNG_SecureRandomImpl.java in the engineNextBytes() method where

bits = seedLength << 3 + 64; 

was changed to

bits = (seedLength << 3) + 64; 

Use SecretKeyFactory() to generate a Secure key instead of secure random.

public class Crypto {

Cipher ecipher;
Cipher dcipher;

byte[] salt = { 1, 2, 4, 5, 7, 8, 3, 6 };
int iterationCount = 1979;

Crypto(String passPhase) {
    try {
        // Create the key
        KeySpec keySpec = new PBEKeySpec(passPhase.toCharArray(), salt, iterationCount);
        SecretKey key = SecretKeyFactory.getInstance("PBEWITHSHA256AND128BITAES-CBC-BC").generateSecret(keySpec);
        ecipher = Cipher.getInstance(key.getAlgorithm()); 
        dcipher = Cipher.getInstance(key.getAlgorithm());

        AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);

        ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
        dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

    } catch (Exception e) {
        // TODO: handle exception
        //Toast.makeText(this, "I cought ", Toast.LENGTH_LONG).show();
    }


}

public String encrypt(String str) {
    String rVal;
    try {
        byte[] utf8 = str.getBytes("UTF8");

        byte[] enc = ecipher.doFinal(utf8);

        rVal = toHex(enc);

    } catch (Exception e) {
        // TODO: handle exception
        rVal = "Exception Caught "+e.getMessage();
    }
    return rVal;
}


public String decrypt(String str) {
    String rVal;
    try {
        byte[] dec = toByte(str);
        byte[] utf8 = dcipher.doFinal(dec);

        rVal = new String(utf8, "UTF8");

    } catch(Exception e) {
        rVal = "Error in decrypting :"+e.getMessage();
    }
    return rVal;
}

private 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;
}
private 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));
}


}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文