Need advice about AES CTR cipher python vs. Java

痴心易碎 提交于 2020-01-01 07:12:46

问题


I'm working on project when some arbitrary data are encrypted using Python simple-crypt (source here) and same encrypted data are then used in java application.

I would like to understand conceptual difference between JSSE and Pycrypto.

This is python part doing encryption (source):

counter = Counter.new(HALF_BLOCK, prefix=salt[:HALF_BLOCK//8])
cipher = AES.new(cipher_key, AES.MODE_CTR, counter=counter)

This is my attempt for java re-implementation of same operation:

SecretKeySpec key = new SecretKeySpec(cipher_key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(salt, 0, HALF_BLOCK / 8);
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);

Problem here is that initialization of java Cipher throw exception:

java.security.InvalidAlgorithmParameterException: IV must be 16 bytes long.
    at org.bouncycastle.jce.provider.JCEBlockCipher.engineInit(Unknown Source)
    at javax.crypto.Cipher.init(Cipher.java:1394)
    at javax.crypto.Cipher.init(Cipher.java:1327)

Value of HALF_BLOCK is 64.

So question is, how does python's AES implementation works with HALF_BLOCK/8 key size and java's not?

Thanks!


回答1:


The nonce (the "left side" of the IV; the "right" being the sequential counter) should be transported alongside the cipher text as the IV. There is no need to keep the nonce secret. It just must not be re-used for another message encrypted by the same key.

It appears the Python code is generating a new Counter which is 64 bits long and sets the prefix (I'm assuming the nonce value) to be the first 8 bytes of the salt variable. It likely (huge assumption here because I don't have access to the Python code) starts the actual counter value at 0x00 * 8, so your initial IV would be:

salt = '#Eg����' # => UTF-8 encoding of 0x0123456789ABCDEF (not familiar enough with Python for the actual expression)
# Really may be misunderstanding, but as the AES IV must be 16 bytes, I imagine the terminology here is prefix = 8 bytes, sequence = 8 bytes
counter = Counter.new(HALF_BLOCK, prefix=salt[:HALF_BLOCK]) # => '0x01234567 89ABCDEF 00000000 00000000'
# Perform one encryption
counter # => '0x01234567 89ABCDEF 00000000 00000001'
# etc.

To perform the same operation in Java, it should be as simple as initializing your IvParameterSpec to the same as above (i.e. right-pad the first 8 bytes of the salt with 0 to 16 bytes).

// Intentionally verbose for demonstration; this can obviously be compacted
byte[] salt = org.bouncycastle.util.encoders.Hex.decode("0123456789ABCDEF");
byte[] nonceAndCounter = new byte[16];
System.arraycopy(salt, 0, nonceAndCounter, 0, ((int) (HALF_BLOCK / 8)));
IvParameterSpec iv = new IvParameterSpec(nonceAndCounter);

Here's a full test case which asserts that the encrypt and decrypt are internally compatible; you could also run this with data from the Python side to verify.

    @Test
    public void testPythonCompatibility() {
        // Arrange
        byte[] cipher_key = org.bouncycastle.util.encoders.Hex.decode("0123456789ABCDEFFEDCBA9876543210");
        final int HALF_BLOCK = 64;
        byte[] salt = org.bouncycastle.util.encoders.Hex.decode("0123456789ABCDEF");
        byte[] nonceAndCounter = new byte[16];
        System.arraycopy(salt, 0, nonceAndCounter, 0, ((int) (HALF_BLOCK / 8)));
        IvParameterSpec iv = new IvParameterSpec(nonceAndCounter);
        Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC");
        SecretKeySpec key = new SecretKeySpec(cipher_key, "AES");
        cipher.init(Cipher.ENCRYPT_MODE, key, iv);

        final String plaintext = "This is a plaintext message.";

        // Act
        byte[] cipherBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

        // Assert
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        byte[] recoveredBytes = cipher.doFinal(cipherBytes);
        String recovered = new String(recoveredBytes, StandardCharsets.UTF_8);
        assert recovered.equals(plaintext);
    }


来源:https://stackoverflow.com/questions/40615753/need-advice-about-aes-ctr-cipher-python-vs-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!