Encoding and byte errors in Ruby using OpenSSL?

I was getting this error:

incompatible encoding regexp match (UTF-8 regexp with ASCII-8BIT string)

when trying to pass a variable from Rails to JavaScript via this line:

window.nonce = '<%= j @nonce %>';

My @nonce variable is an OpenSSL RSA public key encryption created by:

@nonce = Rails.rsaEncUsingPublic(pubKey, randomStr)

def self.rsaEncUsingPublic(key, msg)
    return key.public_encrypt msg
end

I then tried adding force_encoding("UTF-8") to the end of the rsaEncUsingPublic function which changed the error to:

invalid byte sequence in UTF-8

Now I clearly don't want to strip characters from an encrypted variable, however the same encryption function works fine everywhere else, until I'm passing it to JavaScript.

Printing out @nonce (with or without force encoding) does give a lot of gibberish:

                                                            #??7:A}p[??g/?%???=????h9?jg?    W?V?j ?}??G???t?7?i?:"???"#HM?0?L?????*r:?YaB&v&?5m??,???[U?Dt??G???T??&~??6f???????P??<GKV?`? p?K??B???????[?yj6?=?;?
 ???p?j=?Z?? ?[?5i??i?t?!???^?L{;??,??Ma\_mg?|??]A?????"??X:??????;???      ?y??\????#    ]?M" ?
          ?N

@nonce.encoding prints out UTF-8.

@nonce.inspect pints out:

"\u0015\xC0jn\xE7\xBC\xE4\u0016gV\x84&-?+?A:4\xB1(\xC0\xEAv\x91\xE8>\u001D\x92?\xF6\xDC\xEE\x9A)\xC7&O\u001A\x90f?\e\x9Bb*\xF2\xE2\u001E\xB9V\x9E\xBB\x9AU?cU\u001E~\u0011\u0001$?\xF8J\xED\xFE^\"\u001EC\xBD8\u0002\xBA\xDC\xDFI?, KU\u0000\u0014\u0015\x92_w\x95\x89\xD0-OfG\xB5\xF8LC\x9BO\\0j<?\xA5\u001Dw(t?\xA4\xA2\u00174\xB5Š\xE3\x91s\xDA\u0002i\xB3\u0003Q\u000F\xF4\xDB5\x80\xD8\xE0./\x8B\x8A?0\u0001\x91=$T\xCB\bLh\xF3\u001C\xFD\xBF\x95I%=gQ\u000F}\x8F_w\xFAn\x90\x81\xFC\b4\x9E\xC1\xD7y\xBC\xE8\xA4cQY\[email protected]\xD7\xC9+\xA7\xEA>\xA5\xBC\xCF\xC81:TG\xFD\x88\xCCS\x90\xB1\x9Cv\xA3?,\xA1;\xA5\xEE\xE4q9\u0000w\xB9\xB3\u0014\xD9\u0015\x8B\x82nw\ej\x82xkm)\x9Aa\xF1\xDD?\xA2"

All help would be appreciated!

Answers:

Answer

So, the reason it is happening is within j method, exactly in this line:

result = javascript.gsub(/(\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] }

Note the lovely u at the end of the regex. This forced Ruby to fail the match if the given string is not UTF-8 compatible.

Now, when you are encoding a string the result is not meant to be any form of human readable string - it is purely binary and no encoding will display anything useful. Ruby, by default, is trying to display it with 'UTF-8', but this string is not 'UTF-8' compatible as it may contain non-UTF-8 sequences (since it may contain literally anything).

Now the solution won't be easy as this string is not a valid JavaScript string at all. Also, even if you managed to convert it so that JavaScript, JavaScript might save the string representation differently, and the important thing is to keep the binary information unchanged. The easiest way is probably to convert the encrypted string into a number:

window.nonce = '<%= @nonce.unpack('B*').first.to_i(2) %>';

It will result in a number which has a binary representation that is exactly the same as for the encrypted string. You only need to be sure it is handled properly everywhere.

Question: how is this string to be used in JavaScript?

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.