问题
Apparently this used to work on ruby 1.8.7 but unfortunately not on 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
It returns
NoMethodError: undefined method `^' for "V":String
Any idea on how to get this working?
Thanks a lot
回答1:
In 1.8, the String#[] method returned a Fixnum which was the byte at the specified index. In newer version, String#[] returns a String because strings are made of characters and the character-to-byte mapping depends on the encoding. Looks like you're using a String as a byte buffer so you should be working in Array instead of String:
class Array
def xor(key)
a = dup
a.length.times { |n| a[n] ^= key[n % key.size] }
a
end
end
And then to use it:
mangled_array = string.codepoints.to_a.xor(key.codepoints.to_a)
Then if you really want a String (which will contain a bunch of unprintable control characters and zero bytes and such things), then:
mangled_string = mangled_array.inject('') { |s,c| s << c }
And then to unpack:
mangled_string.
codepoints.
to_a.
xor(key.codepoints.to_a).
inject('') { |s,c| s << c }
All of this should maintain UTF-8 all the way through and that's what you want.
You could probably patch your xor
into Enumerable and skip the to_a
business if desired. You could probably also adapt this to patch for String as well.
You shouldn't be using String for byte buffers anymore, you're better off using arrays of Fixnum for that with explicit encoding handling.
回答2:
Call #ord
and #chr
methods to convert from character to it's number representation and back to character
So your example should call:
text.length.times {|n| text[n] = (text[n].ord ^ key[n.modulo key.size].ord).chr }
来源:https://stackoverflow.com/questions/7267548/simple-xor-ruby-1-9-2