Decrypting “SunJCE” AES encrypted data on Android

前端 未结 3 1612
离开以前
离开以前 2021-02-11 04:34

We need to write some Android code to decrypt some data sent from our server. Our server team gave us some sample decryption code which uses the \"SunJCE\" provider, which unfo

相关标签:
3条回答
  • 2021-02-11 05:17

    @Maarten Bodewes was correct: the garbage characters are present in our Java-only module too.

    The problem is that our server side code is padding the input data with zeros before encrypting it. This is so the input matches the block size required for AES.

    There's a good discussion here: Android - Removing padded bits in decryption

    Even though I'm a little uneasy using this "zero padding", here's a utility I wrote to remove it:

    public static String getStringAfterRemovingZeroPadding(byte[] input) {
        if (input == null) {
            return null;
        }
    
        int index = input.length - 1;
    
        while (index >= 0) {
            if (input[index] == 0) {
                // We found some zero padding, look at the next character and see if it's also zero
                // padding
                --index;
            } else {
                // This character is not a zero padding, so go back to the zero padding that we
                // just inspected, or go to the end of the string
                ++index;
                break;
            }
        }
    
        if (index < 0) {
            return "";
        }
    
        return new String(input, 0, index);
    }
    

    ...and here are my unit tests:

    @Test
    public void testRemoveZeroPaddingNull() throws Exception {
        String result = StringUtils.getStringAfterRemovingZeroPadding(null);
        assertThat(result).isNull();
    }
    
    @Test
    public void testRemoveZeroPaddingAllZeros() throws Exception {
        byte[] input = {0, 0};
        String result = StringUtils.getStringAfterRemovingZeroPadding(input);
        assertThat(result).isEqualTo("");
    }
    
    @Test
    public void testRemoveZeroPaddingNoZeros() throws Exception {
        byte[] input = {80, 80, 80};
        String result = StringUtils.getStringAfterRemovingZeroPadding(input);
        assertThat(result).isEqualTo("PPP");
    }
    
    @Test
    public void testRemoveZeroPaddingOneZero() throws Exception {
        byte[] input = {80, 80, 80, 0};
        String result = StringUtils.getStringAfterRemovingZeroPadding(input);
        assertThat(result).isEqualTo("PPP");
    }
    
    @Test
    public void testRemoveZeroPaddingSomeZeros() throws Exception {
        byte[] input = {80, 80, 80, 0, 0, 0, 0, 0};
        String result = StringUtils.getStringAfterRemovingZeroPadding(input);
        assertThat(result).isEqualTo("PPP");
    }
    
    0 讨论(0)
  • 2021-02-11 05:22

    The same garbage is also present in the Java code. It's just that you probably run this on Windows that uses the default Latin (ISO_8859_1) character set and that Android uses UTF-8 by default. It also depends on the console and font used to print out the characters. In this case it is likely that the padding that is used doesn't print on the Windows console but does on the Android code.

    You need to see the byte array (e.g. in hexadecimals) to find out which padding is used and then strip it off before turning the plaintext into a string.

    0 讨论(0)
  • 2021-02-11 05:36

    If you run this code on Android, you'll see what Ciphers are supported:

    TreeSet<String> ciphers = new TreeSet<>();
    for (Provider provider : Security.getProviders())
        for (Service service : provider.getServices())
            if (service.getType().equals("Cipher"))
                ciphers.add(service.getAlgorithm());
    for (String cipher : ciphers)
        System.out.println(cipher);
    

    On Windows 7 with JDK 1.8.0_51, I get:

    AES
    AESWrap
    AESWrap_128
    AESWrap_192
    AESWrap_256
    AES_128/CBC/NoPadding
    AES_128/CFB/NoPadding
    AES_128/ECB/NoPadding
    AES_128/GCM/NoPadding
    AES_128/OFB/NoPadding
    AES_192/CBC/NoPadding
    AES_192/CFB/NoPadding
    AES_192/ECB/NoPadding
    AES_192/GCM/NoPadding
    AES_192/OFB/NoPadding
    AES_256/CBC/NoPadding
    AES_256/CFB/NoPadding
    AES_256/ECB/NoPadding
    AES_256/GCM/NoPadding
    AES_256/OFB/NoPadding
    ARCFOUR
    Blowfish
    DES
    DESede
    DESedeWrap
    PBEWithHmacSHA1AndAES_128
    PBEWithHmacSHA1AndAES_256
    PBEWithHmacSHA224AndAES_128
    PBEWithHmacSHA224AndAES_256
    PBEWithHmacSHA256AndAES_128
    PBEWithHmacSHA256AndAES_256
    PBEWithHmacSHA384AndAES_128
    PBEWithHmacSHA384AndAES_256
    PBEWithHmacSHA512AndAES_128
    PBEWithHmacSHA512AndAES_256
    PBEWithMD5AndDES
    PBEWithMD5AndTripleDES
    PBEWithSHA1AndDESede
    PBEWithSHA1AndRC2_128
    PBEWithSHA1AndRC2_40
    PBEWithSHA1AndRC4_128
    PBEWithSHA1AndRC4_40
    RC2
    RSA
    RSA/ECB/PKCS1Padding
    
    0 讨论(0)
提交回复
热议问题