使用Ruby读取PHP加密的数据


Reading data encrypted with PHP using Ruby

我正在用Ruby系统替换旧的PHP系统。这里的开发人员为我编写了他自己的加密代码(啊)。旧的PHP使用下面的代码来加密一些数据。我很难在ruby中编写"解密"方法。

序言
我意识到这个现有php代码的安全问题(三元组,无盐等)。新的Ruby代码不存储任何敏感数据,但至少需要读取PHP创建的数据。

旧PHP代码

// old PHP code
class encrypter {
  private $_crypt;
  private $_key;
  private $_algorithm;
  private $_mode;
  private $_init_vector;

    public function __construct( $key = 'SomeRandomStringThisOneIsOK', $algorithm = 'tripledes', $mode = 'ecb', $init_vector = false ) {
      $this->_key = $key;
      $this->_algorithm = $algorithm;
      $this->_mode = $mode;
      $this->_init_vector = $init_vector;
      $this->_crypt = mcrypt_module_open($algorithm, '', $mode, '') ;
      $random_seed = MCRYPT_RAND;
      //generate an initialization vector if none is given.
      $init_vector = ($init_vector === false)
        ? mcrypt_create_iv(mcrypt_enc_get_iv_size($this->_crypt), $random_seed)
        : substr($init_vector, 0, mcrypt_enc_get_iv_size($this->_crypt));
      $expected_key_size = mcrypt_enc_get_key_size($this->_crypt);
      // we dont need to know the real key, we just need to be able to confirm a hashed version
      $key = substr(md5($key), 0, $expected_key_size);
      mcrypt_generic_init($this->_crypt, $key, $init_vector);
    }

    public function encrypt($plain_string) {
      return base64_encode(mcrypt_generic($this->_crypt, $plain_string));
    }
    public function decrypt($encrypted_string) {
      return trim(mdecrypt_generic($this->_crypt, base64_decode($encrypted_string)));
    }
    public function __destruct() {
      $this->_crypt = null;
    }
    public function __sleep() {
      $this->_crypt = null;
      return array_keys( get_object_vars( $this ) );
    }
    public function __wakeup () {
      $this->__construct($this->_key, $this->_algorithm, $this->_mode, $this->_init_vector);
    }
  }

我不明白的地方
我不知道如何在Ruby中模拟这一行php。无可否认,因为我不能100%确定php在做什么。

mcrypt_create_iv(mcrypt_enc_get_iv_size($this->_crypt), $random_seed)

Ruby
我计划使用Encryptor Gem(它包装了OpenSSL方法)。我无法在OS X上安装ruby- crypt,并且认为OpenSSL是内置的,所以为什么不使用它。同样,我只需要能够解密数据。

secret = "some_secret_key"
iv = "what goes here?"
Encryptor.default_options.merge!(:algorithm => 'des-ede-cbc', :key => secret)
decrypted_value = Encryptor.decrypt(:value => encrypted_value, :key => secret, :iv => iv)

您突出显示的行创建了一个新的随机初始化向量(IV),用于播种一些加密。IV的长度取决于所使用的算法,mcrypt_enc_get_iv_size返回所使用算法的正确长度。

要解密数据,需要提供用于加密消息的相同初始化向量。您无法从代码中获得此值,因为它每次都会生成一个新的随机值,尽管使用了相当短的随机源(如果没有显式传递给构造函数)。

iv = "这里是什么?"

我相信答案是:

$init_vector = ($init_vector === false)
    ? mcrypt_create_iv(mcrypt_enc_get_iv_size($this->_crypt), $random_seed)
    : substr($init_vector, 0, mcrypt_enc_get_iv_size($this->_crypt));

如果init_vectorfalse,则创建一个随机的iv。否则,使用传递给__construct函数的iv

正如Frederick所说,初始化向量的大小取决于所使用的分组密码,并且可以通过mcrypt_enc_get_iv_size获取。

您已经显示了encryptor类。decryptor类会有一点不同。它将使用现有的iv。它将而不是创建一个,因此应该缺少逻辑。


只是自行车脱落,但这有点弱:

$key = substr(md5($key), 0, $expected_key_size);

有更好的方法来扩展和提取熵。

信息安全堆栈交换或加密堆栈交换的人应该能够帮助熵提取器。他们可能会告诉你使用PBKDF, HKDF或使用HMAC而不仅仅是MD5 (MD5而不是伪随机排列或PRP函数;而HMAC则拥有这个属性)

我最终通过使用下面的ruby实现了这个功能。我不是100%确定为什么,但是Ruby库不需要IV.

Mcrypt.new(:tripledes, :ecb, Digest::MD5.hexdigest(key)[0,24])
plaintext  = crypto.decrypt(Base64.decode64('some_encryped_base_64_encoded_string')).strip