在 python 和 android 中通过 AES 算法加密和解密

Encrypt and Decrypt by AES algorithm in both python and android

我有 python 和 android AES 加密代码。当我在 android 中加密文本时,它在 python 中成功解密,但无法在 android 中解密。有人有想法吗?

Python代码:

import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES


class AESCipher:

    def __init__(self, key):
        self.bs = 16
        self.key = hashlib.sha256(key.encode()).digest()

    def encrypt(self, message):
        message = self._pad(message)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(message)).decode('utf-8')

    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')

    def _pad(self, s):
        return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)

    @staticmethod
    def _unpad(s):
        return s[:-ord(s[len(s)-1:])]

Android代码:

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Arrays;

import android.annotation.SuppressLint;
import android.location.Criteria;
import android.util.Base64;
import android.util.Log;

@SuppressLint("NewApi")
public class Crypt {

private static final String tag = Crypt.class.getSimpleName();

private static final String characterEncoding = "UTF-8";
private static final String cipherTransformation = "AES/CBC/PKCS5Padding";
private static final String aesEncryptionAlgorithm = "AES";
private static final String key = "this is my key";
private static byte[] ivBytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
private static byte[] keyBytes;

private static Crypt instance = null;


Crypt()
{
    SecureRandom random = new SecureRandom();
    Crypt.ivBytes = new byte[16];
    random.nextBytes(Crypt.ivBytes); 
}

public static Crypt getInstance() {
    if(instance == null){
        instance = new Crypt();
    }

    return instance;
}

public String encrypt_string(final String plain) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException
{
    return Base64.encodeToString(encrypt(plain.getBytes()), Base64.DEFAULT);
}

public String decrypt_string(final String plain) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, ClassNotFoundException, IOException
{
    byte[] encryptedBytes = decrypt(Base64.decode(plain, 0));
    return Base64.encodeToString( encryptedBytes, Base64.DEFAULT);
}



public   byte[] encrypt(   byte[] mes)
        throws NoSuchAlgorithmException,
        NoSuchPaddingException,
        InvalidKeyException,
        InvalidAlgorithmParameterException,
        IllegalBlockSizeException,
        BadPaddingException, IOException {

    keyBytes = key.getBytes("UTF-8");
    Log.d(tag,"Long KEY: "+keyBytes.length);
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    md.update(keyBytes);
    keyBytes = md.digest();

    Log.d(tag,"Long KEY: "+keyBytes.length);

    AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
    SecretKeySpec newKey = new SecretKeySpec(keyBytes, aesEncryptionAlgorithm);
    Cipher cipher = null;
    cipher = Cipher.getInstance(cipherTransformation);

    SecureRandom random = new SecureRandom();   
    Crypt.ivBytes = new byte[16];               
    random.nextBytes(Crypt.ivBytes);            

    cipher.init(Cipher.ENCRYPT_MODE, newKey, random);
//    cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
    byte[] destination = new byte[ivBytes.length + mes.length];
    System.arraycopy(ivBytes, 0, destination, 0, ivBytes.length);
    System.arraycopy(mes, 0, destination, ivBytes.length, mes.length);
    return  cipher.doFinal(destination);

}

public   byte[] decrypt(   byte[] bytes)
        throws NoSuchAlgorithmException,
        NoSuchPaddingException,
        InvalidKeyException,
        InvalidAlgorithmParameterException,
        IllegalBlockSizeException,
        BadPaddingException, IOException, ClassNotFoundException {

    keyBytes = key.getBytes("UTF-8");
    Log.d(tag,"Long KEY: "+keyBytes.length);
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    md.update(keyBytes);
    keyBytes = md.digest();
    Log.d(tag,"Long KEY: "+keyBytes.length);

    byte[] ivB = Arrays.copyOfRange(bytes,0,16);
    Log.d(tag, "IV: "+new String(ivB));
    byte[] codB = Arrays.copyOfRange(bytes,16,bytes.length);


    AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivB);
    SecretKeySpec newKey = new SecretKeySpec(keyBytes, aesEncryptionAlgorithm);
    Cipher cipher = Cipher.getInstance(cipherTransformation);
    cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
    byte[] res = cipher.doFinal(codB); 
    return  res;

}


}

当我 运行 这个代码在 android:

String str = "this is local test";
Log.i("myTag", "step1: " + str);
String a = aesCrypt.encrypt_string(str);
Log.i("myTag", "step2: " + a);
String b = aesCrypt.decrypt_string(a);
Log.i("myTag", "step3: " + b);

然后我得到了这个答案:

step1: this is local test
step2: a0F8MhzkSpRlM+aM1MKzUdVCoXIE5y5hh4PRuwPfAhofKwLJjTUbBvmJzTsKJDqF
step3: dGhpcyBpcyBsb2NhbCB0ZXN0

有人知道为什么会这样吗?

您正在对解密后的输出进行编码。

public String decrypt_string(final String plain) throws ...
{
    byte[] encryptedBytes = decrypt(Base64.decode(plain, 0));
    return Base64.encodeToString( encryptedBytes, Base64.DEFAULT);
    //     ^--------------------| this 
}

如果您只加密可打印数据,那么您可以安全地从上面的代码中删除 Base64.encodeToString 调用。要 return 正确的类型,你可以

return new String(encryptedBytes);