2

PyCrypto を使用してデータを復号化しようとしています。データは、javax.crypto パッケージを使用して Java でエンコードされました。暗号化は Triple 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 でエンコードされた文字列の 1 つを取得すると、それをデコードできません。以下は、私が試した 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

つまり、途中で何かが正しくセットアップされていないということです。私はこれに数時間取り組んでおり、 DESedeを実装するSunJCE ソースコードを調べて、使用するデフォルトを確認しようとしましたが、役に立ちませんでした。これを自動的に実行されるスクリプトの一部として使用するので、復号化に Java を使用する必要はありません。データを正しく復号化するために何をする必要があるか知っている人はいますか?

4

1 に答える 1

3

それを機能させるために私がしなければならなかったのは、この行を変更することだけでした

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

これに:

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

これは、Java がキーをエンコードする方法と一致するため、正しい暗号化キーを取得できます。


この質問から何かを学びたいと思ってここに来た場合は、一般的なアドバイスを次に示します。

  1. 想定を再確認してください。キー文字列は 16 進文字列だったので、そのように使用されていると想定しました。
  2. 自分の仮定が何であるかを確認してください: キーがどのように使用されるかについて、どのように仮定しているのかを意識的に考えていませんでした。これは、プログラミングと一般的な生活の両方で非常に頻繁に発生する傾向があります。
  3. 途中ですべての値を確認してください (特にOracleを使用している場合): バイト配列の値を確認することで、私の問題に気づきました。
于 2013-04-25T17:12:57.957 に答える