Java-Python AES加密解密 - java

我有一个使用AES的Java(v8)加密文本,我正在尝试使用相同的SecretKey,Salt在python中解密,但是在取消索引超出范围时遇到问题。当我进行反向操作时,即在python中加密并在java中解密,那么我能够获取文本,但带有一些不需要的前缀。

以下是我尝试过的java和python代码。

Java代码(来自org.apache.commons.codec.binary.Base64的Base64)

public static String encrypt(String secretKey, String salt, String value) throws Exception {
        Cipher cipher = initCipher(secretKey, salt, Cipher.ENCRYPT_MODE);
        byte[] encrypted = cipher.doFinal(value.getBytes());
        return Base64.encodeBase64String(encrypted);
    }

    public static String decrypt(String secretKey, String salt, String encrypted) throws Exception {
        Cipher cipher = initCipher(secretKey, salt, Cipher.DECRYPT_MODE);
        byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
        return new String(original);
    }

    private static Cipher initCipher(String secretKey, String salt, int mode) throws Exception {

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");

        KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt.getBytes(), 65536, 256);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKeySpec skeySpec = new SecretKeySpec(tmp.getEncoded(), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(mode, skeySpec, new IvParameterSpec(new byte[16]));
        return cipher;
    }

    public static void main(String[] args) throws Exception {
        String secretKey = "Secret";
        String fSalt = "tJHnN5b1i6wvXMwzYMRk";
        String plainText = "England";

        String cipherText = encrypt(secretKey, fSalt, plainText);
        System.out.println("Cipher: " + cipherText);
//      cipherText = "6peDTxE1xgLE4hTGg0PKTnuuhFC1Vftsd7NH9DF/7WM="; // Cipher from python
        String dcrCipherText = decrypt(secretKey, fSalt, cipherText);
        System.out.println(dcrCipherText);

    }

Python代码(3.6版)和Pycrypto V2.6

import base64
import hashlib
import os

from Crypto.Cipher import AES

BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)

# unpad = lambda s: s[:-ord(s[len(s) - 1:])]
unpad = lambda s: s[0:-s[-1]]

def get_private_key(secretKey, salt):
    key = hashlib.pbkdf2_hmac('SHA256', secretKey.encode(), salt.encode(), 65536, 32)
    return key


def encrypt(message, salt, secretKey):
    private_key = get_private_key(secretKey, salt)
    message = pad(message)
    iv = os.urandom(BS)  # 128-bit IV
    cipher = AES.new(private_key, AES.MODE_CBC, iv, segment_size=256)
    return base64.b64encode(iv + cipher.encrypt(message))


def decrypt(enc, salt, secretKey):
    private_key = get_private_key(secretKey, salt)
    enc = base64.b64decode(enc)
    iv = enc[:BS]
    cipher = AES.new(private_key, AES.MODE_CBC, iv, segment_size=256)
    return unpad(cipher.decrypt(enc[BS:]))


secretKey = "Secret"
salt = "tJHnN5b1i6wvXMwzYMRk"
plainText = "England"
cipher = encrypt(plainText, salt, secretKey)
print("Cipher: " + bytes.decode(cipher))

# cipher = "0JrZdg9YBRshfTdr1d4zwQ==" # Cipher from java
decrypted = decrypt(cipher, salt, secretKey)
print("Decrypted " + bytes.decode(decrypted))

当我传递python密码时,Java解密输出:�U�����or���England,应为:England
Python解密输出:unpad = lambda s : s[0:-s[-1]]
IndexError: index out of range
,预期:England

关于此问题,我也在堆栈上浏览了其他文章,但是由于他们使用了不同的模式,因此无法解决。

参考方案

在python中,您将iv(初始化向量)存储在加密消息的前16个字节中。

在Java中,您没有做任何事情-您传递了一个空的IV,并将包括前16个字节的整个消息视为密文。

您需要确保Java和Python匹配。

两者都不使用IV,在这种情况下,您要在Python中删除该部分。

或者,您同时使用IV,在这种情况下,您需要更新Java代码以生成随机的加密IV,并将其添加到加密结果中。解密时,Java代码需要将前16个字节作为IV,并将其传递给Cipher

Java:找到特定字符并获取子字符串 - java

我有一个字符串4.9.14_05_29_16_21,我只需要获取4.9。数字各不相同,所以我不能简单地获得此char数组的前三个元素。我必须找到最正确的.并将其子字符串化直到那里。我来自Python,因此我将展示Python的实现方法。def foobar(some_string): location = some_string.rfind('.&…

python-构造函数中的另一个类 - java

我是Python的新手,我很难理解如何在Python中执行以下操作(例如,在Java中的操作方式)class Person{ private String name; private Address address; public Person(String xyz, Address a) { this.name = xyz; this.address = …

通过更改会话中的PATH将Python指向本地保存的64位Java吗? - java

Python当前默认为32-bit Java,因为它已安装在企业计算机上,并且导致某些软件包的兼容性问题。我无权在Windows本身中安装64-bit。因此,作为替代方案,我试图将Python指向本地保存的Java的64-bit版本,以便将其用于会话,而不修改Windows中的整体功能。有没有办法做到这一点?我似乎可以使用以下代码行在Rstudio中做到这一…

如何使用正则表达式匹配以相反顺序排列的后两个字符为前两个字符的任何字符串 - java

Closed. This question needs to be more focused。它当前不接受答案。                                                                                                                            …

如何从Java执行python脚本? - java

我有一个python脚本,需要从Java运行python脚本。这该怎么做? 参考方案 一种选择是使用jython(用Java编写的Python)。如果不合适,则可以使用Runtime.exec()派生/执行脚本过程。但是,使用它可能有点麻烦,请查看this article中常见的陷阱。