Converting a hexadecimal digest to base64 in Ruby
Seems pretty clear and efficient to me. You can save the call to strip by specifying 0 count for the 'm' pack format (if count is 0, no line feed are added, see RFC 4648)
def hex_to_base64_digest(hexdigest)
[[hexdigest].pack("H*")].pack("m0")
end
How to convert hexadecimal to base64urlsafe?
The following should do it:
Base64.urlsafe_encode64(Array(hex_string).pack('H*'))
The method urlsafe_encode64
expects binary input, so you need to convert the hex representation to binary first, as shown above.
Convert Python's base64.b64encode(hmac.new().hexdigest()) to Ruby
First, '\n'
in Ruby means literally \
and n
. To represent newline, you need to use double-quoted string: "\n"
.
The order of parameter of Digest::HMAC.hexdigest
is different from python version. And according to the Digest::HMAC
documetation, its usage is discouraged. Use OpenSSL:HMAC
instead.
So the ruby script should be read as:
require 'base64'
require 'openssl'
key = ''
text = "GET\n\n\nSat, 22 Mar 2014 13:49:42 +0000\n"
# hex = Digest::HMAC.hexdigest(text, key, Digest::SHA1) # <-- discouraged
hex = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), key, text)
p Base64.urlsafe_encode64(hex)
# => "ZmUxN2YxMDQxMTdlODg3MDljMTRjYjY0ZGU1NDk1MjgwNzI2Yjk1Zg=="
Convert Between Digest::MD5.digest and Digest::MD5.hexdigest
Using then unpack method will do the trick. (Checkout the official documentation)
Digest::MD5.digest('http://www.example.com').unpack('H*').first == Digest::MD5.hexdigest('http://www.example.com')
Why is hex - base64 so different from base64 - hex using pack and unpack?
to_hex
is the exact inverse of to_base64
:
to_base64
- put string in an array:
[self]
- call pack with
H*
:[self].pack("H*")
- put string in an array:
[[self].pack("H*")]
- call pack with
m0
:[[self].pack("H*")].pack("m0")
to_hex
- call unpack with
m0
:self.unpack("m0")
- extract string from array:
self.unpack("m0").first
- call unpack with
H*
:self.unpack("m0").first.unpack("H*")
- extract string from array:
self.unpack("m0").first.unpack("H*").first
That's how you undo operations, by applying the inverse operations:
a = 5
(a + 4) * 3
#=> 27
And the other way around:
a = 27
(a / 3) - 4
#=> 5
a.pack
is the inverse of a.unpack
and a.first
is the inverse of [a]
How to convert a Base64 encoded string to UUID format
I was familiar with unpack
but this prompted me to learn the directive as pointed out by cremno.
simplest form:
b64 = 'FWLalpF2T5mmyxS03Q+hNQ0K'
b64.unpack("m0").first.unpack("H8H4H4H4H12").join('-')
#=> "1562da96-9176-4f99-a6cb-14b4dd0fa135"
b64.unpack("m0")
give us:
#=> ["\x15b\xDA\x96\x91vO\x99\xA6\xCB\x14\xB4\xDD\x0F\xA15\r\n"]
which is an array so we use .first
to grab the string and unpack again using the directive to format it in the 8-4-4-4-12 format:
b64.unpack("m0").first.unpack("H8H4H4H4H12")
gives us:
#=> ["1562da96", "9176", "4f99", "a6cb", "14b4dd0fa135"]
an array of strings, so now we just join it with the -
:
b64.unpack("m0").first.unpack("H8H4H4H4H12").join('-')
#=> "1562da96-9176-4f99-a6cb-14b4dd0fa135"
With Ruby, how to convert binary data to highly compressed, but readable, format
A simple method uses Base64 encoding to encode the value. It's very similar to Hex encoding (which is Base16), but uses a longer dictionary.
Base64 strings, when properly prepared, contain only printable characters. This is a benefit for copy/paste and for sharing.
The secondary benefit is that it has a 3:4 encoding ratio, which means that it's reasonably efficient. A 3:4 encoding ration means that for each 3 bytes in the input, 4 bytes are used to encode (75% efficient); Hex encoding is a less efficient 1:2 encoding ratio, or for each 1 byte of input, 2 bytes are used to encode (50% efficient).
You can use the Ruby standard library Base64 implementation to encode and decode, like so:
require "base64"
encoded = Base64.encode64("Taste the thunder!") # <== "VGFzdGUgdGhlIHRodW5kZXIh\n"
decoded = Base64.decode64(encoded) # <== "Taste the thunder!"
Note that there is a (mostly) URL-safe version, as well, so that you can include an encoded value anywhere in a URL without requiring any additional URL encoding. This would allow you to pass information in a URL in an obscured way, and especially information that normally wouldn't be easily passed in that manner.
Try this to encode your data:
encoded_url_param = Base64.urlsafe_encode64("cake+pie=yummy!") # <== "Y2FrZStwaWU9eXVtbXkh"
decoded_url_param = Base64.urlsafe_decode64(encoded_url_param) # <== "cake+pie=yummy!"
Using Base64 in a URL, while actually not "security", will help keep prying eyes from your data and intent. The only potential downside to using Base64 values in a URL is that the URL must remain case-sensitive, and some applications don't honor that requirement. See the Should URL be case sensitive SO question for more information.
Ruby version of CryptoJS Base64 stringify
CrytoJS' HmacSHA1
returns binary data whereas Ruby's hexdigest
returns a (hex-encoded) string representation.
To get the same result, have to base64-encode the binary digest
instead:
secret = 'NzAwZmIwMGQ0YTJiNDhkMzZjYzc3YjQ5OGQyYWMzOTI='
signature = "date: Mon, 25 Jul 2016 16:36:07 GMT\nx-mod-nonce: 28154b2-9c62b93cc22a-24c9e2-5536d7d"
hmac = OpenSSL::HMAC.digest('sha1', secret, signature)
#=> "X\x13+\xFD\x87a\xCA\xC6\xE6\x88\x81$u:\xDF\xDA\x13\xFBI\xF0"
Base64.strict_encode64(hmac)
#=> "WBMr/YdhysbmiIEkdTrf2hP7SfA="
Ruby pack and unpack. How is this hexadecimal conversion being done? Could use some assistance
encrypted_message
is a string starting with the characters .YI
. Let's convert those characters to Hex and then binary using the ASCII table:
ASCII . |Y |I
Hex 2 e |5 9 |4 9
Binary 0010 1110|0101 1001|0100 1001
Notice that the hex is what you see at the beginning of the unpack(H*)
result. If you were to call encrypted_message.unpack("B*")
(bit string), you would similarly see it start with
001011100101100101001001
The point is
- There is no "encrypted message format".
encrypted_message
is meaningless, structureless binary data. - When you call
unpack
, you're saying "Take this meaningless binary data, and show it to me with a different representation." In this case, hexadecimal digits. You can similarly see it as binary, like I did above. Or you can look at it as ASCII characters (the default), with\x
indicating a byte that doesn't have an ASCII representation. It's all the same binary data just being presented in different human-readable ways.
Related Topics
How to Overwrite a Printed Line in the Shell with Ruby
Setting Path for Whenever in Cron So It Can Find Ruby
Difference Between Integer(Value) and Value.To_I
Which Ruby Version am I Really Running
Ruby-Debug19 on Ruby-1.9.3-Preview1
Replace "&" to "\&" in Ruby Seems Impossible
How to Dump Strings in Yaml Using Literal Scalar Style
Is There an Equivalent Null Prevention on Chained Attributes of Groovy in Ruby
How to Add to a Serialized Array
How to Create Wizard Forms in Ruby on Rails
What Is '-Mix' in a Ruby Regular Expression
Handling Exceptions Raised in a Ruby Thread
How Is Each_With_Object Supposed to Work
Finding If a Sentence Contains a Specific Phrase in Ruby
Rails Active Admin CSS Conflicting with Twitter Bootstrap CSS