【问题标题】:De/Encrypting file as stream with PHP and Java - Padding?使用 PHP 和 Java 将文件解/加密为流 - 填充?
【发布时间】:2014-05-27 01:29:54
【问题描述】:

我正在尝试使用 PHP 加密相当大的文件(最大 150mb)并使用 Java 解密它们。

当我使用 Java 对其进行加密并将其与 PHP 的加密结果进行比较时,我发现最后几个字节不同。

这可能是填充的问题吗?我该如何解决这个问题?

Java 代码能够正确地加密和解密文件。

下面的代码根本不安全,也不应该是安全的。

PHP 加密:

    public function encodeAndEncrypt($source, $target, $keyPhrase) {
    $hSrc = fopen($source,'rb');
    $hDst = fopen($target,'wb');

    $iv = substr(md5($keyPhrase, true), 0, 8);
    $key = substr(md5($keyPhrase, true), 0, 24);
    $opts = array('iv'=>$iv, 'key'=>$key);

    stream_filter_append($hDst, 'mcrypt.tripledes', STREAM_FILTER_WRITE, $opts);


    while ($chunk = fread($hSrc,8192)) {
            fwrite($hDst,$chunk, 8192);
    }

    fclose($hDst);
    fclose($hSrc);

Java解密:

private static final String ALGORITHM = "DESede/CBC/PKCS5Padding";


    void main() {

    MessageDigest md = MessageDigest.getInstance("md5");
    byte[] digestOfPassword = md.digest("O".getBytes("UTF-8"));
    byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
    byte[] ivBytes = Arrays.copyOf(digestOfPassword, 8);
    final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
    FileInputStream fis = new FileInputStream(new File("7za920.zip.enc"));
    FileOutputStream fos = new FileOutputStream(new File("7za920.zip"));
    decrypt(key, ivBytes, fis, fos);
    }


    private static void decrypt(SecretKey key, byte[] iv, InputStream is, OutputStream os) {
    try {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
        CipherInputStream cis = new CipherInputStream(is, cipher);
        doCopy(cis, os);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    private static void doCopy(InputStream is, OutputStream os) throws IOException {
    try {
        byte[] bytes = new byte[4096];
        int numBytes;
        while ((numBytes = is.read(bytes)) != -1) {
            os.write(bytes, 0, numBytes);
        }
        } finally {
            is.close();
            os.close();
        }
    }

    // only for demonstration
    private static byte[] encrypt(SecretKey key, IvParameterSpec iv, InputStream is, OutputStream os) {
    try {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key, iv);
        CipherInputStream cis = new CipherInputStream(is, cipher);
        doCopy(cis, os);
        return cipher.getIV();
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

【问题讨论】:

  • 如果您也发布ALGORITHM 的定义会很有帮助。没有它,就根本没有提到 java 版本中使用的填充。
  • 哦,拍摄 - 我添加了它。谢谢。此外,Java 代码工作(在 Java 中加密和解密工作正常。在 PHP 中加密和在 Java 中解密没有。因此我认为 PHP 代码有问题(文件仅在最后几个字节不同,其余的被正确解密) )。

标签: java php encryption mcrypt


【解决方案1】:

基本上,正如 Perseids 指出的那样,mcrypt 对任何严重的事情都不利。

有趣的是,我发现这段代码可以正常工作。它可能会使用更多的内存,但它可以工作。

再说一次,这是不安全的。我只用它来混淆愚蠢的病毒扫描代理。

    public function encrypt($source, $target, $keyPhrase) {
            $iv = substr(md5($keyPhrase, true), 0, 8);
            $key = substr(md5($keyPhrase, true), 0, 24);
            $file = file_get_contents('../filesfile.zip');
            $Encrypt = mcrypt_encrypt(MCRYPT_3DES, $key, $file, MCRYPT_MODE_CBC, $iv);
            $fpE = fopen($target, 'wb') or die("can't open file");
            fwrite($fpE, $Encrypt);
            fclose($fpE);

    }

【讨论】:

    【解决方案2】:

    是的,您的现象与不同的填充策略有关。 Java 实现使用PKCS5(相当于PKCS7),而PHP 实现使用zero padding(参见Parameteres->data 下),即如果消息不够大,则添加零字节。

    对于未来的问题,我会要求您做一些更彻底的初步研究。对于我的答案,我只是按照您的指示查看代码以查看实际指定的填充,用谷歌搜索mcrypt 使用的默认填充并且已经是答案。

    【讨论】:

    • 谢谢。我最初的研究得出了相同的结果 - 但我该如何解决这个问题?
    • @PhilW 显然你必须自己实现填充。有关实现,请参阅stackoverflow.com/a/7448878/371137。坦率地说,mcrypt 看起来真的很糟糕(另一个例子:如果密钥不够长,则填充零。严重吗? O.o)如果你可以放弃它,就这样做。
    猜你喜欢
    • 2014-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-29
    • 1970-01-01
    • 2013-09-25
    • 2012-05-11
    • 1970-01-01
    相关资源
    最近更新 更多