Simple XOR ruby 1.9.2



显然这曾经在ruby 1.8.7上工作,但不幸的是在1.9.2上不起作用

class String
  def xor(key)
    text = dup
    text.length.times {|n| text[n] ^= key[n.modulo key.size] }
    text
  end
end
def encode(_original, _pass = 'testvendor')
  _original.xor(_pass)
end
puts encode('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.')
#output=>    
8
EE
DEBDREBDEVSR
TTTT
TNZV0D
SE E    CRVSETENR   D
TT
    EKS0DSO VD
EVVTE S 
RSREXE+E T
 RR
T _TOEDE RO E
TTD
K

它返回

NoMethodError:未定义方法' ^' for "V":String

有什么办法让它工作吗?

Thanks to lot

在1.8中,String#[]方法返回一个Fixnum,即指定索引处的字节。在较新的版本中,String#[]返回String,因为字符串是由字符组成的,字符到字节的映射依赖于编码。看起来你正在使用字符串作为字节缓冲区,所以你应该在数组中工作,而不是字符串:

class Array
  def xor(key)
     a = dup
     a.length.times { |n| a[n] ^= key[n % key.size] }
     a
  end
end

然后使用它:

mangled_array = string.codepoints.to_a.xor(key.codepoints.to_a)

如果你真的想要一个字符串(它将包含一堆不可打印的控制字符和零字节之类的东西),那么:

mangled_string = mangled_array.inject('') { |s,c| s << c }

然后解包:

mangled_string.
  codepoints.
  to_a.
  xor(key.codepoints.to_a).
  inject('') { |s,c| s << c }

所有这些都应该一直保持UTF-8,这就是你想要的。

如果需要的话,您可以将xor补丁到Enumerable中并跳过to_a业务。

你不应该再使用String作为字节缓冲区了,你最好使用带有显式编码处理的Fixnum数组

调用#ord#chr方法从字符转换为数字表示,然后再转换回字符

所以你的例子应该调用:

text.length.times {|n| text[n] = (text[n].ord ^ key[n.modulo key.size].ord).chr }

最新更新