如何使用可以使用gpg解密的对称AES256使用Ruby加密文件?

时间:2014-12-21 20:41:18

标签: ruby encryption

如何使用以下约束在Ruby中创建加密文件?

  1. 数据是由不受信任的用户提供的字节数组。
  2. 密码是由不受信任的用户提供的字节数组。
  3. 密码接受所有常用的密码字符,包括password special characters(例如“,”等)。
  4. 文件格式应该是常用的格式,例如OpenPGP。
  5. 加密文件将发回给用户。
  6. 注意:在误解后澄清问题。

3 个答案:

答案 0 :(得分:2)

如果您安装了GPG,那么可以采用快速,简便,可靠的方式:

open("| gpg [options]","w"){|f| f.syswrite(data) }

示例:

require 'shellwords'
data = "Hello World"
password = "letmein" 
gpg = "/usr/local/bin/gpg \
  --symmetric \
  --cipher-algo aes256 \
  --digest-algo sha256 \
  --cert-digest-algo sha256 \
  --batch --yes \
  --passphrase #{password.shellescape} \
  --output /tmp/out.gpg
" 
open("| #{gpg}","w"){|f| f.syswrite(data) }

通常,使用系统的内置GPG更安全,而不是尝试管理自己的加密。

答案 1 :(得分:0)

解决了这个问题,而无需通过与openssl进行互操作来生成进程:

更新:请参阅我使用gpg的其他答案

@@OPENSSL_MAGIC = "Salted__"
@@DEFAULT_CIPHER = "aes-256-cbc"
@@DEFAULT_MD = OpenSSL::Digest::SHA256

# Note: OpenSSL "enc" uses a non-standard file format with a custom key
# derivation function and a fixed iteration count of 1, which some consider
# less secure than alternatives such as OpenPGP/GnuPG
#
# Resulting bytes when written to #{FILE} may be decrypted from the command
# line with `openssl enc -d -#{cipher} -md #{md} -in #{FILE}`
#
# Example:
#  openssl enc -d -aes-256-cbc -md sha256 -in file.encrypted
def encrypt_for_openssl(
  password,
  data,
  cipher = @@DEFAULT_CIPHER,
  md = @@DEFAULT_MD.new
)
  salt = SecureRandom.random_bytes(8)
  cipher = OpenSSL::Cipher::Cipher.new(cipher)
  cipher.encrypt
  cipher.pkcs5_keyivgen(password, salt, 1, md)
  encrypted_data = cipher.update(data) + cipher.final
  @@OPENSSL_MAGIC + salt + encrypted_data
end

# Data may be written from the command line with
# `openssl enc -#{cipher} -md #{md} -in #{INFILE} -out #{OUTFILE}`
# and the resulting bytes may be read by this function.
#
# Example:
#  openssl enc -aes-256-cbc -md sha256 -in file.txt -out file.txt.encrypted
def decrypt_from_openssl(
  password,
  data,
  cipher = @@DEFAULT_CIPHER,
  md = @@DEFAULT_MD.new
)
  input_magic = data.slice!(0, 8)
  input_salt = data.slice!(0, 8)
  cipher = OpenSSL::Cipher::Cipher.new(cipher)
  cipher.decrypt
  cipher.pkcs5_keyivgen(password, input_salt, 1, md)
  c.update(data) + c.final
end

这基于forge.js security library,特别是example to match openssl's enc toolusing an iteration count of 1

答案 2 :(得分:0)

ruby-gpgmeopenpgp似乎都不行,因此产生gpg似乎是目前最好的方法。

require "openssl"
require "digest/sha2"
require "open3"
require "tempfile"

....

@@OPENPGP_DEFAULT_CIPHER = "AES256"
@@DEFAULT_MD = OpenSSL::Digest::SHA512

# Return symmetrically encrypted bytes in RFC 4880 format which can be
# read by GnuPG or PGP. For example:
# $ gpg --decrypt file.pgp
#
# ruby-gpgme doesn't seem to work: https://github.com/ueno/ruby-gpgme/issues/11
# openpgp doesn't seem to work: https://github.com/bendiken/openpgp/issues/2
# Therefore we assume gpg is installed and try to spawn out to it
def encrypt_for_pgp(
  password,
  data,
  cipher = @@OPENPGP_DEFAULT_CIPHER,
  md = @@DEFAULT_MD.new
)
  input_file = Tempfile.new('input')
  begin
    input_file.write(data)
    input_file.close
    output_file = Tempfile.new('output')
    begin
      Open3.popen3(
        "gpg --batch --passphrase-fd 0 --yes --homedir /tmp/ " +
        "--cipher-algo #{cipher} --s2k-digest-algo #{md.name} " +
        "-o #{output_file.path} --symmetric #{input_file.path}"
      ) do |stdin, stdout, stderr, wait_thr|
        stdin.write(password)
        stdin.close_write
        exit_status = wait_thr.value
        if exit_status != 0
          raise "Exit status " + exit_status.to_s
        end
      end
      output_file.close
      return IO.binread(output_file.path)
    ensure
      output_file.unlink
    end
  ensure
    input_file.unlink
  end
end