Подтвердить что ты не робот

Простое шифрование в Ruby без внешних камней

Мне нужно простое шифрование для некоторых текстовых строк. Я хочу создать коды купонов и заставить их выглядеть круто, поэтому впоследствии созданный код должен выглядеть совсем по-другому. (И, кроме того, выглядя круто, это не должно быть легко угадать код.) Но я хочу иметь возможность расшифровать их снова. Таким образом, алгоритм должен быть обратимым.

Я пробовал некоторые вещи с движущимися битами, чтобы они выглядели как бы случайные. Но два последующих кода (только один бит разный), конечно, очень похожи.

Любые предложения? Я хотел бы сделать это без использования внешних драгоценных камней.

Филипп

4b9b3361

Ответ 1

Решение отчасти с нуля, но основано на этом: https://math.stackexchange.com/questions/9508/looking-for-a-bijective-discrete-function-that-behaves-as-chaotically-as-possib

Самый простой из представленных способов - использование a * x + b (mod 2^n)

Очевидно, что это не настоящее шифрование, а действительно полезное, если вы хотите создавать последовательные коды купонов без большого количества кода.

Итак, чтобы реализовать это, сначала нужно выбрать a, b и n. (a должно быть нечетным) Например, a=17, b=37 и n=27. Также нам нужно найти " a^(-1) " на "mod 2 ^ n". Это можно сделать на https://www.wolframalpha.com с помощью функции ExtendedGcd:

enter image description here

Таким образом, обратное a, следовательно, 15790321. Собираем все это вместе:

A=17
B=37
A_INV=15790321

def encrypt(x)
  (A*x+B)%(2**27)
end

def decrypt(y)
  ((y-B)*A_INV)%(2**27)
end

И теперь вы можете сделать:

irb(main):038:0> encrypt(4)
=> 105
irb(main):039:0> decrypt(105)
=> 4

Очевидно, мы хотим, чтобы коды купонов выглядели круто. Таким образом, необходимы 2 дополнительные вещи: начните последовательность с 4000 или около того, чтобы коды были длиннее. Также конвертируйте их в нечто буквенно-цифровое, что также легко с Ruby:

irb(main):050:0> decrypt("1ghx".to_i(36))
=> 4000
irb(main):051:0> encrypt(4000).to_s(36)
=> "1ghx"

Еще одним приятным дополнительным свойством является то, что последовательные числа достаточно различны, поэтому угадывание практически невозможно. Конечно, мы предполагаем, что пользователи не криптоаналитики, и если кто-то действительно угадает действительное число, это не конец света: :-)

irb(main):053:0> encrypt(4001).to_s(36)
=> "1gie"
irb(main):054:0> decrypt("1gie".to_i(36))
=> 4001

Давайте попробуем наивно "взломать" его, считая от 1gie до 1gif:

irb(main):059:0* decrypt("1gif".to_i(36))
=> 15794322

Это абсолютно вне диапазона, в любом случае есть только около 2000 купонов, а не миллион. :-) Также, если я правильно помню, можно немного поэкспериментировать с параметрами, поэтому последующие числа выглядят более хаотично.

(Выберите большее n для более длинных кодов и наоборот. База 36 означает, что для каждого символа требуется 6 битов (" Math.log(36, 2) "). Таким образом, n=27 допускает до 5 символов.)

Ответ 2

Вы можете использовать OpenSSL:: Cypher

# for more info, see http://ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Cipher.html

require 'openssl'
require 'digest/sha1'

# create the cipher for encrypting
cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
cipher.encrypt

# you will need to store these for later, in order to decrypt your data
key = Digest::SHA1.hexdigest("yourpass")
iv = cipher.random_iv

# load them into the cipher
cipher.key = key
cipher.iv = iv

# encrypt the message
encrypted = cipher.update('This is a secure message, meet at the clock-tower at dawn.')
encrypted << cipher.final
puts "encrypted: #{encrypted}\n"

# now we create a sipher for decrypting
cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
cipher.decrypt
cipher.key = key
cipher.iv = iv

# and decrypt it
decrypted = cipher.update(encrypted)
decrypted << cipher.final
puts "decrypted: #{decrypted}\n"

Но промежуточная форма не поддается печати


Учитывая, что было бы хорошо, если бы промежуточная форма была одинаковой длины, вы могли бы просто использовать простую карту одного char для другого.

ПОЖАЛУЙСТА, ПОНИМАЙТЕ, ЧТО ЭТО НЕ БЕЗОПАСНО

Вы можете легко перетащить ключ, но он, похоже, соответствует вашим требованиям.

class Cipher

  def initialize(shuffled)
    normal = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + [' ']
    @map = normal.zip(shuffled).inject(:encrypt => {} , :decrypt => {}) do |hash,(a,b)|
      hash[:encrypt][a] = b
      hash[:decrypt][b] = a
      hash
    end
  end

  def encrypt(str)
    str.split(//).map { |char| @map[:encrypt][char] }.join
  end

  def decrypt(str)
    str.split(//).map { |char| @map[:decrypt][char] }.join
  end

end

# pass the shuffled version to the cipher
cipher = Cipher.new ["K", "D", "w", "X", "H", "3", "e", "1", "S", "B", "g", "a", "y", "v", "I", "6", "u", "W", "C", "0", "9", "b", "z", "T", "A", "q", "U", "4", "O", "o", "E", "N", "r", "n", "m", "d", "k", "x", "P", "t", "R", "s", "J", "L", "f", "h", "Z", "j", "Y", "5", "7", "l", "p", "c", "2", "8", "M", "V", "G", "i", " ", "Q", "F"]

msg = "howdy pardner"

crypted = cipher.encrypt msg
crypted # => "1IzXAF6KWXvHW"

decrypted = cipher.decrypt crypted
decrypted # => "howdy pardner"

Ответ 3

Если вам не нужно настоящее шифрование, вы можете использовать простой шифр. (Это можно использовать, когда вам не нужна безопасность, или для шифрования коротких случайных/одноразовых строк.)

ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

#generated with ALPHABET.split('').shuffle.join
ENCODING = "MOhqm0PnycUZeLdK8YvDCgNfb7FJtiHT52BrxoAkas9RWlXpEujSGI64VzQ31w"

def encode(text)
  text.tr(ALPHABET, ENCODING)
end

def decode(text)
  text.tr(ENCODING, ALPHABET)
end

Ответ 4

Для базовой цели кодирования/декодирования я предполагаю, что встроенная библиотека Base64 Ruby может быть удобной:

2.2.1 :001 > require 'base64'
 => true 
2.2.1 :002 > str = "[email protected]"
 => "[email protected]" 
2.2.1 :003 > Base64.encode64(str)
 => "YWJjQGV4YW1wbGUuY29t\n" 

Он также имеет методы версии urlsafe, если кодированные строки должны использоваться в URL-адресах.

Ссылка: http://ruby-doc.org/stdlib-2.3.0/libdoc/base64/rdoc/Base64.html

Ответ 5

Я могу порекомендовать вам uuencode и uudecode utils вы можете использовать их в стандартном рубиновом пакете функций:

str = "\007\007\002\abcde"
new_string = [str].pack("u")
original = new_string.unpack("u")

(образец из Рубинового пути Хала Фултона)

Ответ 6

Дополнительный метод для шифрования и дешифрования

gem 'activesupport'

require 'active_support'

key = SecureRandom.random_bytes(32)
crypt = ActiveSupport::MessageEncryptor.new(key)
encrypted_data = crypt.encrypt_and_sign("your password")
password = crypt.decrypt_and_verify(encrypted_data)

Ответ 7

Вы действительно хотите доверять пользователю, чтобы вернуть правильное значение? Если вы доверяете тому, что клиент возвращает вам, а пользователь определяет схему шифрования, вы будете использовать данные, которые они предоставляют. Это звучит как очень плохая идея.

Мне непонятно, почему вы не хотите давать им ключ в базу данных, которая отображает случайные числа, возможно, с некоторыми свойствами исправления ошибок, на купонные скидки. Таким образом, вы контролируете конечный результат. Они предоставляют вам ключ, вы просматриваете соответствующий купон и применяете купон. Таким образом, вы используете только свои собственные данные, и если вы хотите удалить купон, все это на стороне сервера.

Если вы сохраните все коды клавиш, вы также можете проверить, что новые коды отличаются от ранее выпущенных.

Ответ 8

Вы можете проверить все различные способы шифрования/дешифрования с помощью ruby ​​в этом контексте: https://gist.github.com/iufuenza/183a45c601a5c157a5372c5f1cfb9e3e

Если вы не хотите использовать драгоценный камень, я бы полностью рекомендовал Openssl как наиболее безопасный, который также очень легко реализовать, так как он имеет очень хорошую поддержку Ruby.

Ответ 9

Я знаю, что вы ищете шифрование без драгоценных камней, но все же хотите предложить его тем, кто здесь и не беспокоится об использовании внешних драгоценных камней. Попробуйте glogin (я автор):

require 'glogin/codec'
codec = GLogin:Codec.new('the secret')
encrypted = codec.encrypt('Hello, world!')
decrypted = codec.decrypt(encrypted)

Он основан на OpenSSL и Base58.