Base64.encode64 in Ruby split the resulting string
Be careful when using Base64 library and the encode64 function. Unpleasant feature of this function is that after every 60 characters add to the resulting string “\n”.
This functionality is also described in the documentation:
Returns the Base64-encoded version of bin. This method complies with RFC 2045. Line feeds are added to every 60 encoded characters.
We can look at the function definition:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# Returns the Base64-encoded version of +bin+. # This method complies with RFC 2045. # Line feeds are added to every 60 encoded charactors. # # require 'base64' # Base64.encode64("Now is the time for all good coders\\nto learn Ruby") # # <i>Generates:</i> # # Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g # UnVieQ== def encode64(bin) [bin].pack("m") end |
And try this example:
1 2 |
require 'base64' Base64.encode64("Now is the time for all good coders\\nto learn Ruby") |
The result of this example is a string that contains a newlines characters:
1 2 3 |
"Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g\\n UnVieQ==\\n " |
Where is the problem
The problem occurs when we decode this string, for example in PHP, which expected to classic base64 string.
1 2 |
var_dump(base64_decode('dGhpcyBpcyBteSBsb2duIHZlcmkgbG9uZyBzdHJpbmcgd2hpdGNoIG5ld2xp\\nbmUgY2hhcmFjdGVz\\n')); var_dump(base64_decode('dGhpcyBpcyBteSBsb2duIHZlcmkgbG9uZyBzdHJpbmcgd2hpdGNoIG5ld2xpbmUgY2hhcmFjdGVz') ); |
The result of this code is as follows:
1 2 |
string(58) "this is my logn veri long string whitch newliťą”Ťˇ…É…ŤŃ•Î" string(57) "this is my logn veri long string whitch newline charactes" |
A string that contains a newline charactes is decoded incorrectly.
The correct solution
The first solution is to do replace these characters with gsub function:
1 2 |
require 'base64' irb(main):005:0> Base64.encode64("Now is the time for all good codersnto learn Ruby").gsub("\n", '') |
The result is without a newline character:
1 |
Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4gUnVieQ== |
The correct solution is to use the strict_encode64 function:
1 2 |
require 'base64' Base64.strict_encode64("Now is the time for all good coders\\nto learn Ruby") |
The result is the same as that by replacing newlines:
1 |
"Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4gUnVieQ==" |