2014-12-21 6 views
2

Как создать зашифрованный файл в Ruby со следующими ограничениями?Как зашифровать файл с помощью Ruby с помощью симметричного AES256, который можно расшифровать с помощью gpg?

  1. Данные представляют собой массив байтов, предоставленных ненадежным пользователем.
  2. Пароль - это массив байтов, предоставленный ненадежным пользователем.
  3. Пароль принимает все часто используемые символы пароля, в том числе password special characters (например,»и т.д.).
  4. Формат файла должен быть широко используемый формат, такой как OpenPGP.
  5. зашифрованный файл отправляется обратно в . пользователь

. Примечание: Вопрос выяснены после ошибки

+0

GPG использует формат OpenPGP, описанный в http://tools.ietf.org/html/rfc4880 – Kevin

ответ

0

Ни ruby-gpgme, ни openpgp, похоже, работают хорошо, поэтому нерестовый 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 
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, а не пытаться управлять своей собственной криптографией.

+2

«В общем, это более безопасно использовать систему встроенного в GPG, а не пытаться управлять своим собственным крипто. ". Вероятнее всего. Воспользуйтесь заранее подготовленными и проверенными колесами, особенно для чего-то сложного, как шифрование. –

+0

В качестве альтернативы правилам экранирования пароля (как показано в примере, 'password = 'x; mkdir/tmp/danger; #' 'вводит произвольный код оболочки), я опубликовал еще один ответ, ниже которого отправляется пароль через STDIN – Kevin

+0

Всегда защищать строки с внешними входами, например путем экранирования, удаления, проверки и т. д. – joelparkerhenderson

0

решаемые это без необходимости порождать процесс совместной работе с OpenSSL:

Update: Смотрите другие мои ответ использовать 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 tool и using an iteration count of 1.

+0

@joelparkerhenderson Что такое ошибка? – Kevin

+0

@joelparkerhenderson Я отредактировал свой ответ, чтобы добавить, откуда появилась моя реализация, в частности, библиотека безопасности forge.js; однако после дальнейшего расследования я обнаружил некоторые опасения по поводу неизменяемого количества итераций OpenSSL, равного 1, что упрощает попытку попытки перебора силы, и я буду дополнительно исследовать это: [«« счетчик итераций »задается enc команда на 1 и не может быть изменена »] (http://security.stackexchange.com/questions/29106/openssl-recover-key-and-iv-by-passphrase) – Kevin

+0

Открытые проблемы https://github.com/digitalbazaar/forge/issues/209 и https://github.com/mdp/gibberish/issues/18. проблема с forge.js разрешена с обновленным README: "(Примечание: OpenSSL« enc »использует нестандартный формат файла с функцией деривации пользовательского ключа и фиксированным числом итераций 1, которые некоторые считают менее безопасными, чем альтернативы, такие как OpenPGP/GnuPG)» – Kevin

Смежные вопросы