【问题标题】:Python Decrypting with Crypto: first 16 characters are gibberishPython 用 Crypto 解密:前 16 个字符是乱码
【发布时间】:2021-03-12 22:39:29
【问题描述】:

我正在尝试解密使用AES/CBC/PKCS5Padding 在 Java 中加密的文件。但是,我在完全解密文件时遇到了一些麻烦。我想我错过了一些简单的东西。我对加密很陌生,所以这很有可能:

import base64
import re

from Crypto import Random
from Crypto.Cipher import AES

# generate the key
passphrase = "my_secret_passphrase"
key = passphrase[0:16].encode()

# load in the encrypted file as bytes
file_name = "tbd/enc.csv"
with open(file_name, "rb") as in_file:
    encrypted_bytes = in_file.read()

# initialize the cipher
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)

# use the cipher to decrypt the bytes
decrypted_bytes = cipher.decrypt(encrypted_bytes)

# write to an out_file
file = re.sub("\.csv", "_decoded.csv", file)
with open(file, "wb") as binary_file:
    binary_file.write(decrypted_bytes)

这是我得到的第一行文字:

M¢p†‘GW§'tÄ%èéired Date,Employees - Id,First,Employees - Middle,Last,Employees - Preferred Name,Job Title,Employees - Marital Status,Employees - Trade Code,...

我注意到前 16 个字符完全是胡言乱语,所以我知道我很接近了。我可能会丢失什么导致前 16 个字符无法正确解码?奇怪的是我们能够在java中解密整个文件,所以我们知道它的python实现有问题。

奖金回合:用于加密文件的java代码(我没有编码也不知道java):

package rpa.ipaengine.bots.cmic.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class TestFile {
  private static Logger LOGGER = LoggerFactory.getLogger(TestFile.class);
  public static void main(String[] args) {
    LOGGER.info("running");
    try {
      Security.setProperty("crypto.policy", "unlimited");
      encryptedFile("my_secret_passphrase", "/tbd/enc.csv", "tbd/dec.csv");
      decryptedFile("my_secret_passphrase", "/tbd/enc.csv", "tbd/dec.csv");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static void encryptedFile(String secretKey, String fileInputPath, String fileOutPath)
    throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException, IllegalBlockSizeException,
    BadPaddingException {
    try {
      byte[] raw1 = "my_secret_passphrase"
        .getBytes();
      byte[] raw = new String(raw1, 0, 16).getBytes();
      Key skeySpec = new SecretKeySpec(raw, "AES");
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
      byte[] iv = new byte[cipher.getBlockSize()];
      IvParameterSpec ivParams = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParams);
      var fileInput = new File(fileInputPath);
      var inputStream = new FileInputStream(fileInput);
      var inputBytes = new byte[(int) fileInput.length()];
      inputStream.read(inputBytes);
      var outputBytes = cipher.doFinal(inputBytes);
      var fileEncryptOut = new File(fileOutPath);
      var outputStream = new FileOutputStream(fileEncryptOut);
      outputStream.write(outputBytes);
      inputStream.close();
      outputStream.close();
      System.out.println("File successfully encrypted!");
      System.out.println("New File: " + fileOutPath);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  public static void decryptedFile(String secretKey, String fileInputPath, String fileOutPath)
    throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException, IllegalBlockSizeException,
    BadPaddingException, InvalidAlgorithmParameterException {
    try {
      byte[] raw1 = "my_secret_passphrase"
        .getBytes();
      byte[] raw = new String(raw1, 0, 16).getBytes();
      Key skeySpec = new SecretKeySpec(raw, "AES");
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
      byte[] iv = new byte[cipher.getBlockSize()];
      IvParameterSpec ivParams = new IvParameterSpec(iv);
      cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParams);
      var fileInput = new File(fileInputPath);
      var inputStream = new FileInputStream(fileInput);
      var inputBytes = new byte[(int) fileInput.length()];
      inputStream.read(inputBytes);
      byte[] outputBytes = cipher.doFinal(inputBytes);
      var fileEncryptOut = new File(fileOutPath);
      var outputStream = new FileOutputStream(fileEncryptOut);
      outputStream.write(outputBytes);
      inputStream.close();
      outputStream.close();
      System.out.println("File successfully decrypted!");
      System.out.println("New File: " + fileOutPath);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

【问题讨论】:

  • 只是一个猜测:在 AES CBC 中,它通常会在数据中添加随机字节。就像加密时相同的消息是不同的。也许你看到了这些随机字节,也许 java 实现正在跳过它们。
  • 前 16 个字节出现乱码表明您使用了错误的 IV。您当然不应该在解密时使用随机 IV,您应该将它与密文一起获取。查看 Java 代码,看起来他们使用的是全零 IV(这很糟糕)。尝试使用 16 个零字节作为 IV 而不是随机字节(抱歉,我不知道如何在 Python 中创建它)。
  • 经过一番搜索,我认为只需 bytes(16) 即可为您提供您想要测试的内容。
  • 安全警告:请不要使用 Java 代码,因为它是 UNSECURE。它使用原始字符串作为密钥并使用 (x0's) 固定初始化向量,这使得完整的加密易受攻击。此外,密钥没有编码处理,因此代码在不同平台上工作时可能会失败。

标签: java python csv encryption aes


【解决方案1】:

按照马特的建议使用bytes(16),我能够完全破译文本:

import base64
import re

from Crypto import Random
from Crypto.Cipher import AES

# generate the key
passphrase = "my_secret_passphrase"
key = passphrase[0:16].encode()

# load in the encrypted file as bytes
file_name = "tbd/enc.csv"
with open(file_name, "rb") as in_file:
    encrypted_bytes = in_file.read()

# initialize the cipher
iv = bytes(16)
cipher = AES.new(key, AES.MODE_CBC, iv)

# use the cipher to decrypt the bytes
decrypted_bytes = cipher.decrypt(encrypted_bytes)

# write to an out_file
file = re.sub("\.csv", "_decoded.csv", file)
with open(file, "wb") as binary_file:
    binary_file.write(decrypted_bytes)

文件的第一行:

Employees - Hired Date,Employees - Id,First,Employees - Middle...

不过,Michael 提供了一些关于用于加密文件的 Java 代码的有效 cmets。我将与我的团队一起确保它更安全。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多