32

我需要对一些文本字符串进行简单的加密。我想创建优惠券代码并使它们看起来很酷,因此随后创建的代码应该看起来非常不同。(除了看起来很酷之外,猜测代码应该不容易。)但我希望能够再次解密它们。所以算法一定是可逆的。

我已经尝试过一些带有移动位的东西,所以它们看起来已经有点随机了。但是随后的两个代码(只是有点不同)当然看起来非常相似。

有什么建议么?我想在不使用外部宝石的情况下做到这一点。

菲利普

4

9 回答 9

53

你可以使用 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"

但是中间形式不适合印刷


鉴于您认为如果中间形式的长度相同会很好,您可以只使用一个字符到另一个字符的简单映射。

请理解这不安全

您可以轻松地暴力破解密钥,但它似乎符合您的要求。

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"
于 2010-11-08T23:53:18.557 回答
27

如果您不需要真正的加密,则可以使用简单的密码。(这可以在您不需要安全性或加密短随机/一次性字符串时使用。)

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
于 2015-07-29T22:07:48.850 回答
16

可选的加密和解密方法

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)
于 2018-05-09T09:57:05.020 回答
10

对于基本的编码/解码目的,我猜 ruby​​ 的内置 Base64 库可以很方便:

2.2.1 :001 > require 'base64'
 => true 
2.2.1 :002 > str = "abc@example.com"
 => "abc@example.com" 
2.2.1 :003 > Base64.encode64(str)
 => "YWJjQGV4YW1wbGUuY29t\n" 

它还具有urlsafe版本方法,以防编码字符串用于 url。

参考:http ://ruby-doc.org/stdlib-2.3.0/libdoc/base64/rdoc/Base64.html

于 2016-02-17T12:25:18.853 回答
5

解决方案是从头开始的,但基于此: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=37n=27。我们还需要a^(-1)在“mod 2^n”上找到“”。可以使用 ExtendedGcd 函数在https://www.wolframalpha.com上执行此操作:

在此处输入图像描述

因此 的倒数a15790321。把所有这些放在一起:

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

让我们尝试通过从1gieto数数来天真地“破解”它1gif

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

这完全超出了范围,反正只有 2000 张左右的优惠券 - 不是一百万。:-) 另外,如果我没记错的话,可以对参数进行一些试验,因此后续数字看起来更混乱。

(为更长的代码选择更大n的,反之亦然。基本36意味着6每个字符(“”)都需要位Math.log(36, 2)。因此n=27最多允许 5 个字符。)

于 2010-11-13T16:58:06.693 回答
3

我可以向您推荐 uuencode 和 uudecode 实用程序,您可以使用它们来使用标准 ruby​​ 功能包:

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

(来自 Hal Fulton 的 Ruby Way 示例)

于 2010-11-08T23:11:49.973 回答
2

你真的想相信用户会给你正确的价值吗?如果您相信客户回馈给您的内容并且用户找出您的加密方案,那么您将使用他们提供的数据。这听起来是个非常糟糕的主意。

我不清楚为什么您不想将密钥提供给将随机数(可能具有一些纠错属性)映射到优惠券折扣的数据库。这样您就可以控制最终结果。他们为您提供一个密钥,您查找相关联的优惠券并应用优惠券。通过这种方式,您只使用自己的数据,如果您想删除优惠券,这一切都在服务器端。

如果您保留所有密钥代码,您还可以检查新代码是否与以前发布的代码不同。

于 2010-11-09T17:58:53.540 回答
1

您可以在此要点中使用 ruby​​ 检查所有不同的加密/解密方式:https ://gist.github.com/iufuenza/183a45c601a5c157a5372c5f1cfb9e3e

如果你不想使用 gem,我完全推荐 Openssl 作为最安全的,因为它有很好的 Ruby 支持,所以也很容易实现。

于 2017-07-30T22:30:01.977 回答
-1

我知道您正在寻找无宝石加密,但仍想提供给那些在这里并且不担心使用外部宝石的人。试试glogin(我是作者):

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

它基于 OpenSSL 和 Base58。

于 2019-07-04T10:07:47.397 回答