【问题标题】:Mimicking PHP openssl_encrypt() and openssl_decrypt() call in Perl在 Perl 中模仿 PHP openssl_encrypt() 和 openssl_decrypt() 调用
【发布时间】:2016-06-19 23:27:15
【问题描述】:

我正在尝试编写一些 Perl 代码来解码 PHP 程序生成的 Triple DES (3DES) 密钥。我找了一个在 Perl 中使用Crypt::GCrypt 解码的示例,但找不到。

我需要一个等同于 PHP 的 openssl_decode() 的 Perl,但即使是字符串的加密/解密也不匹配。

这是我的测试代码。所有数值均为测试样本。

use strict;

{
    # match PHP's openssl_encrypt($plain_text, 'des3', $pw, 0, $iv );
    #             openssl_decrypt($cipher_text,'des3', $pw, 0, $iv );
    #   $ee = Exxx->new( %args );
    #   $cipher_text = $ee->encode( $plain_text );
    #   $plain_text  = $ee->decode( $cipher_text );

    package Exxx;

    use Crypt::GCrypt;
    use HTML::Entities;
    use MIME::Base64;

    my $ex_           = 0;
    my $exxx_method   = $ex_ ++;
    my $exxx_password = $ex_ ++;
    my $exxx_iv       = $ex_ ++;
    my $exxx_cipher   = $ex_ ++;

    sub new {
        my ( $class, $method, $passwd, $iv ) = @_;

        my $type = ref($class) ? ref($class) : __PACKAGE__;

        my $this = [];

        $this->[$exxx_method] = $method ? $method : '3des';
        $this->[$exxx_method] = '3des'    # map any PHP name to a Perl name
                if $this->[$exxx_method] eq 'des3';

        $this->[$exxx_password] = pack(
            'H*',
            $passwd ? $passwd
            : '0123456789ABCDEF' .      # key 1
              'FEDCBA9876543210' .      # key 2
              '3243F6A8885A308D' );     # key 3

        $this->[$exxx_iv] = pack(
            'H*',
            $iv ? $iv
            : '2b7e151628aed2a6' );

        bless $this, $type;

        return $this;
    }


    sub _cipher {
        my ( $this, $encrypting_decrypting ) = @_;

        my $cipher = Crypt::GCrypt->new(
            type      => 'cipher',
            algorithm => $this->[$exxx_method],
            mode      => 'cbc',
            padding   => 'standard',
        );

        $cipher->start($encrypting_decrypting);

        $cipher->setiv( $this->[$exxx_iv] );

        return $cipher;
    }


    sub encrypt {
        my ( $this, $plain_text ) = @_;

        my $cipher = $this->_cipher("encrypting");
        $cipher->encrypt($plain_text);

        my $encrypted = $cipher->finish();

        return encode_base64( $encrypted, "" );
    }


    sub encrypt_html {
        my ( $this, $plain_html ) = @_;
        return $this->encrypt( decode_entities($plain_html) );
    }


    sub decrypt {
        my ( $this, $crypt_text ) = @_;

        my $cipher     = $this->_cipher("decrypting");
        my $plain_text = $cipher->decrypt( decode_base64($crypt_text) );
        my $f          = $cipher->finish();

        return $plain_text;
    }
}

############################

my $exit          = 0;
my $plain         = 'Hello, world';                #clear text for both PHP and PERL
my $encrypted_php = 'c0WJDTwtcBsj1vTfTi7jwA==';    #crypted from PHP program

my $exxx = Exxx->new('des3');

my $encrypted = $exxx->encrypt($plain);

if ( $encrypted eq $encrypted_php ) {
    print "PASS encrypt:  (perl)$encrypted eq (php)$encrypted_php\n";
}
else {                                             #trouble.... does not match PHP
    print STDERR "ERROR encrypt: (perl)$encrypted ne (php)$encrypted_php\n";
    $exit = 1;
}

my $decrypted = $exxx->decrypt($encrypted);

if ( $plain eq $decrypted ) {                      #trouble.... does not match PHP
    print "PASS decrypt:  (perl)$plain == (perl)$decrypted\n";
    $exit = 1;
}

{                                                  #trouble.... does not match PHP
    print STDERR "ERROR decrypt: (perl)$plain ne (perl)$decrypted\n";
    $exit = 1;
}

exit $exit;

【问题讨论】:

  • 最终测试值为Y2IA5Q74o2Y/7QjVY9Qk7T5P/pK4SZy/eR2kufFYY5iYET3RbH4zx7UziSzR/yDqYw2jE2pZogVXpdtaWL85nbM1pFMyf+RtFCWJlYWMuhQ=
  • 如果您有任何选择不使用 3DES,请使用 AES(高级加密标准)。当然你不需要安全3DES就可以了。
  • @吉尔伯特:哇。我从未如此努力地使某人的 Perl 代码清晰易读。 阅读使用markdown的帮助(有一个链接,一个橙色圆圈中的问号,在每个打开编辑的帖子的右上角)和 永远不要如果可以的话,不要使用 HTML 标记
  • 我已经尝试过你的代码,但我很难提供帮助。我无法理解您是如何学会这样编写 Perl 的,因为尽管在块中使用 package 并将对象基于数组引用是完全有效的,但对于大多数有经验的 Perl 程序员来说,它们并不熟悉。我建议你将你的包Exxx 写在一个名为Exxx.pm 的单独文件中,然后在你的主代码中写use Exxx。这将有助于隔离任何错误,并且是面向对象编程的主要优势之一
  • 这个my $type = ref($class) ? ref($class) : __PACKAGE__ 太可怕了。它试图支持您应该能够在类的任何实例上调用构造函数的误解,并且还会忽略作为第一个参数传递的任何其他内容,除非它是引用。这将破坏继承,并且像Exxx::new({}) 这样的非法调用将导致HASH 对象,因为没有这样的包,它会中断。这应该只是$type = $class,也许是ref $type and die

标签: php perl libgcrypt


【解决方案1】:

我建议您使用出色的 Crypt::Cipher 库套件。它涵盖了大量的密码,它独立于任何其他模块,我已经使用 Visual C 以及 gcc 和 g++ 成功编译了它,没有任何问题

您需要在创建新的Crypt::Cipher 对象时指定DES_EDE(与Triple DES3DES 相同),其余的应该是显而易见的

Crypt::Cipher->new('DES_EDE', $key);

【讨论】:

    猜你喜欢
    • 2023-03-12
    • 2020-12-21
    • 1970-01-01
    • 2019-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多