shadowsocks/crypto2

aes encryption result is incorrect

Opened this issue · 4 comments

java code

public static String AESEncrypt(String plainText, SecretKey key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        if (ObjectUtils.isEmpty(plainText)) return plainText;
        Cipher aesCipher = Cipher.getInstance("AES");
        aesCipher.init(Cipher.ENCRYPT_MODE, key);
        return Base64.getEncoder().encodeToString(aesCipher.doFinal(plainText.getBytes()));
    }

public static void main(String[] args) {
        String key = "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
        String before = "James";
        try {
            String after = AESEncrypt(before, new SecretKeySpec(Base64.getDecoder().decode(key), "AES"));
            System.out.println(before);
            System.out.println(after);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
}

java code ouput

James
u9QmnI+gjMUK9LETbm2eWA==

rust code

pub fn test_aes(&self, password: String, data: String) -> String {
        let key = base64::decode(password).unwrap();
        let cipher = Aes256::new(key.as_slice());
        let mut text = data.as_bytes().clone().to_owned();
        cipher.encrypt(&mut text);
        return base64::encode(text);
    }

pub fn test(&self) {
        let password = "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=".to_string();
        let data = "James".to_string();
        println!("{}\n{}", data.clone(), self.test_aes(password, data));
    }

rust code ouput

James
vWkOWA0=

base64("12345678901234567890123456789012") = "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI"

aes online result
image

Is there anything wrong with how I use it?

Your key length is not 32 bytes.

len(12345678901234567890123456789012) = 32

len(12345678901234567890123456789012) = 32

This is not a key. The key should be a slice of 32 bytes, not a string of 32 characters.

The correctness is already tested with these testcases:

#[test]
fn test_aes128() {
// AES 128
let key = hex::decode("000102030405060708090a0b0c0d0e0f").unwrap();
let plaintext = hex::decode("00112233445566778899aabbccddeeff").unwrap();
let cipher = Aes128::new(&key);
let mut ciphertext = plaintext.clone();
cipher.encrypt(&mut ciphertext);
assert_eq!(
&ciphertext[..],
&hex::decode("69c4e0d86a7b0430d8cdb78070b4c55a").unwrap()[..]
);
let mut cleartext = ciphertext.clone();
cipher.decrypt(&mut cleartext);
assert_eq!(&cleartext[..], &plaintext[..]);
}
#[test]
fn test_aes192() {
let key = hex::decode("000102030405060708090a0b0c0d0e0f1011121314151617").unwrap();
let plaintext = hex::decode("00112233445566778899aabbccddeeff").unwrap();
let cipher = Aes192::new(&key);
let mut ciphertext = plaintext.clone();
cipher.encrypt(&mut ciphertext);
assert_eq!(
&ciphertext[..],
&hex::decode("dda97ca4864cdfe06eaf70a0ec0d7191").unwrap()[..]
);
let mut cleartext = ciphertext.clone();
cipher.decrypt(&mut cleartext);
assert_eq!(&cleartext[..], &plaintext[..]);
}
#[test]
fn test_aes256() {
// AES 256
let key =
hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap();
let plaintext = hex::decode("00112233445566778899aabbccddeeff").unwrap();
let cipher = Aes256::new(&key);
let mut ciphertext = plaintext.clone();
cipher.encrypt(&mut ciphertext);
assert_eq!(
&ciphertext[..],
&hex::decode("8ea2b7ca516745bfeafc49904b496089").unwrap()[..]
);
let mut cleartext = ciphertext.clone();
cipher.decrypt(&mut cleartext);
assert_eq!(&cleartext[..], &plaintext[..]);
}

AES is a symmetric cipher algorithm, which means that the cipher text's length should be identical with the text. Your Java output:

James
u9QmnI+gjMUK9LETbm2eWA==

should have included some kind of padding, because it is exactly 16bytes length (128-bits), which is AES's block length.

A little bit of searching shows that:

For Oracle JDK 7 (tested), the default cipher for AES is AES/ECB/PKCS5Padding. The Java Security documentation doesn't mention about this though (http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html#algspec), have to do some JUnit testing to find out.