【问题标题】:Decrypting data in Python that was encrypted in 3DES by Java在 Python 中解密由 Java 以 3DES 加密的数据
【发布时间】:2013-04-24 22:56:39
【问题描述】:

我正在尝试使用 PyCrypto 解密数据。数据使用 javax.crypto 包在 Java 中编码。加密是三重 DES(在 Java 中称为“DESede”)。据我所知,默认设置用于所有内容。但是,当我去用 Python 解密数据时,数据总是有问题。

这是加密/解密的 Java 代码:

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import java.security.spec.KeySpec;

public final class Encrypter
{
    public static final String DESEDE_ENCRYPTION = "DESede";

    private KeySpec keySpec;
    private SecretKeyFactory keyFactory;
    private Cipher cipher;

    private static final String UNICODE_FORMAT = "UTF8";

    public Encrypter(String encryptionKey)
        throws Exception
    {
        byte[] keyAsBytes = encryptionKey.getBytes(UNICODE_FORMAT);
        keySpec = new DESedeKeySpec(keyAsBytes);
        keyFactory = SecretKeyFactory.getInstance(DESEDE_ENCRYPTION);
        cipher = Cipher.getInstance(DESEDE_ENCRYPTION);
    }

    public String encryptString(String unencryptedString)
    {
        SecretKey key = keyFactory.generateSecret(keySpec);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] cleartext = unencryptedString.getBytes(UNICODE_FORMAT);
        byte[] ciphertext = cipher.doFinal(cleartext);

        BASE64Encoder base64encoder = new BASE64Encoder();
        return base64encoder.encode(ciphertext);
    }

    public String decryptString(String encryptedString)
    {
        SecretKey key = keyFactory.generateSecret(keySpec);
        cipher.init(Cipher.DECRYPT_MODE, key);
        BASE64Decoder base64decoder = new BASE64Decoder();
        byte[] ciphertext = base64decoder.decodeBuffer(encryptedString);
        byte[] cleartext = cipher.doFinal(ciphertext);

        return bytesToString(cleartext);
    }

    private static String bytesToString(byte[] bytes)
    {
        StringBuilder sb = new StringBuilder();
        for (byte aByte : bytes)
        {
            sb.append((char) aByte);
        }
        return sb.toString();
    }
}

但是,当我采用此代码生成的 base64 编码字符串之一时,我无法对其进行解码。这是我尝试过的一些 python 代码的示例:

from Crypto.Cipher import DES3
import array

key = <value of the key, as a hex string>
encryptedvalue = <the value that's encrypted, as a string>
keyarray = array.array('B', key.decode("hex"))
des = DES3.new(keyarray)
value = des.decrypt(encryptedvalue.decode('base64'))

value.decode('utf-8') # Gives me an error

我遇到的错误类似于

UnicodeDecodeError: 'utf8' codec can't decode byte 0xa7 in position 6: invalid start byte

这意味着在此过程中的某个地方,我没有正确设置某些东西。我已经为此工作了几个小时,甚至试图查看SunJCE source code,其中implements DESede,以查看它们使用的默认值,但无济于事。我将把它用作自动运行的脚本的一部分,所以我真的宁愿不必使用 Java 来进行解密。有谁知道我需要做什么才能正确解密我的数据?

【问题讨论】:

  • 不知道 python,但出现错误,似乎 python 正在尝试解码一个没有等效 Unicode 值的 utf-8 编码值。
  • 不确定你应该如何将数据从java传递到python,但我认为你的问题在于数据传输,其中python接收端的编码变得不同,这可能需要在base64解码之前处理utf-8
  • 我建议的另一件事是检查 python 如何解码 base64 和 utf-8 的默认设置。它可能与 java 设置不同。
  • 我认为你不需要解码价值。您是否尝试过仅打印您从解码中获得的内容?此外,我相当确定如果您在 Java 中使用两个参数 init 方法作为密码,那么它将生成一个随机初始化向量。您需要确保 Java 和 Python 之间的 IV 相同。
  • @Pace 这是我试图深入研究源代码的原因之一——Java 代码在加密或解密时没有指定 IV。如果它使用 IV,它必须使用一些默认的 IV 值,否则 Java 解密将不起作用。

标签: java python encryption pycrypto 3des


【解决方案1】:

我所要做的就是改变这一行

keyarray = array.array('B', key.decode("hex"))

到这里:

keyarray = array.array('B', key.encode("utf-8"))

这与 java 对密钥进行编码的方式相匹配,使我能够拥有正确的加密密钥。


如果您来到这里希望从这个问题中学到一些东西,这里有一些一般性建议:

  1. 仔细检查您的假设:密钥字符串是十六进制字符串,所以我认为它是这样使用的。
  2. 确保您知道您的假设是什么:我没有有意识地考虑我是如何假设密钥的使用方式的。这往往是编程和生活中非常常见的问题。
  3. 检查所有沿途的值(尤其是当你有Oracle时):查看字节数组中的值是让我意识到我的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-22
    • 2012-11-20
    相关资源
    最近更新 更多