web-dev-qa-db-ja.com

Ruby外部gemなしの単純な暗号化

一部のテキスト文字列には単純な暗号化が必要です。クーポンコードを作成して見栄えをよくしたいので、その後作成されるコードは非常に異なって見えるはずです。 (そして、見栄えが良いだけでなく、コードを推測するのは簡単なことではありません。)しかし、それらを再度解読できるようにしたいと思います。したがって、アルゴリズムは可逆的でなければなりません。

私はすでにビットを動かしていくつかのものを試したので、それらはすでにランダムに見えます。ただし、2つの後続のコード(1ビットだけ異なる)はもちろん非常によく似ています。

助言がありますか?私は、外部の宝石を使わずにそれをしたいと思います。

フィリップ

23
Philip

ソリューションはゼロからの一種ですが、これに基づいています: 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_。また、「mod 2 ^ n」で「a^(-1)」を見つける必要があります。 ExtendedGcd関数を使用して https://www.wolframalpha.com でこれを行うことが可能です:

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"
_

素晴らしい追加のプロパティの1つは、連続する数値が十分に異なるため、推測が事実上不可能であるということです。もちろん、ユーザーは暗号アナリストではないと想定しており、誰かが実際に有効な番号を推測したとしても、それは世界の終わりではありません::-)

_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
Philip

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から別のcharへの単純なマップを使用するだけかもしれません。

これはIS安全ではないであることを理解してください

キーをブルートフォースすることは簡単にできますが、要件と一致しているようです。

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"
47
Joshua Cheek

実際の暗号化が必要ない場合は、単純な暗号を使用できます。 (これは、セキュリティが必要ない場合、または短いランダムな/一度限りの文字列を暗号化する場合に使用できます。)

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
17
Ari

暗号化と復号化のオプションの方法

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)
9
Prashanth Sams

基本的なエンコード/デコードの目的では、Rubyに組み込まれているBase64ライブラリが便利だと思います。

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" 

また、エンコードされた文字列がURLで使用される場合に備えて、urlsafeバージョンのメソッドもあります。

参照: http://Ruby-doc.org/stdlib-2.3.0/libdoc/base64/rdoc/Base64.html

8
Jignesh Gohel

Uuencodeとuudecodeutilsを使用することをお勧めします。標準Ruby関数パック:

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

(ハルフルトンのRuby Way)からのサンプル

3
rsludge

ユーザーを信頼して正しい値を返すことを本当に望んでいますか?クライアントがあなたに返すものを信頼し、ユーザーがあなたが提供するデータを使用する暗号化スキームを理解している場合。それは非常に悪い考えのように聞こえます。

おそらくいくつかのエラー訂正プロパティを使用して、乱数をクーポン割引にマップするデータベースにキーを与えたくない理由は私にはわかりません。そうすれば、最終結果を管理できます。彼らはあなたに鍵を提供し、あなたは関連するクーポンを調べてクーポンを適用します。このように、あなたはあなた自身のデータだけを使用していて、あなたがクーポンを削除したいなら、それはすべてサーバー側にあります。

すべてのキーコードを保持している場合は、新しいコードが以前にリリースされたものと異なることを確認することもできます。

2
Paul Rubel

Rubyを使用して、暗号化/復号化のさまざまな方法をすべて確認できます: https://Gist.github.com/iufuenza/183a45c601a5c157a5372c5f1cfb9e3e

Gemを使用したくない場合は、Opensslを最も安全なものとして完全にお勧めします。Opensslは非常に優れたRubyサポートを備えているため、実装も非常に簡単です。

1
user2373148

あなたがジェムなしの暗号化を探していることは知っていますが、それでもここにいて外部ジェムの使用について心配しない人に提供したいと思っています。試してください glogin (私は作者です):

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

OpenSSLとBase58に基づいています。

0
yegor256