This is a C# code:
byte[] pb = System.Text.Encoding.UTF8.GetBytes(policy.ToString());
// Encode those UTF-8 bytes using Base64
string policyB = Convert.ToBase64String(pb);
// Sign the policy with your Secret Key using HMAC SHA-1.
System.Security.Cryptography.HMACSHA1 hmac = new System.Security.Cryptography.HMACSHA1();
hmac.Key = System.Text.Encoding.UTF8.GetBytes(secretKey);
byte[] signb = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(policyB));
string signature = Convert.ToBase64String(signb);
How to do the same in Ruby on rails? More specifically I need to know functions to get bytes from string and base64 encode them and calculate hmac hash.
Not sure if it exactly the same, but it works for me:
#policy = ActiveSupport::Base64.encode64s(#policy)
# Sign policy with secret key
digest = OpenSSL::Digest::Digest.new('sha1')
#signature = ActiveSupport::Base64.encode64s(OpenSSL::HMAC.digest(digest, secretKey, #policy))
I'll try again.
There are a couple of HMAC libraries for ruby/rails that might make this much simpler:
http://auth-hmac.rubyforge.org/
Related
I am trying to port java code that verifies a signature. To generate said signature, a string is first hashed with a SHA-256 digest, then base64 encoded then signed.
The Java code to verify the signature:
public static boolean ver(X509Certificate cert, String data, String sig) throws Exception {
byte[] hashOnly = MessageDigest.getInstance("SHA-256").digest(
data.getBytes(StandardCharsets.UTF_8)
);
String hashWithEncode = Base64.getEncoder().encodeToString(hashOnly);
byte[] encodedDataBytes = hashWithEncode.getBytes();// Byte array of payload that is signed
byte[] decodedSignature = Base64.getDecoder().decode(sig);// Get byte[] of signature string from payload
Signature verifier = Signature.getInstance("SHA256withRSA");
verifier.initVerify(cert.getPublicKey());
verifier.update(encodedDataBytes);
return( verifier.verify(decodedSignature) );
}
Note the data is first hashed, then encoded, then the signature is verified. This will correctly verify a signature
My Ruby code is:
def ver(cert, signature, data)
pub_key = cert.public_key
digest = OpenSSL::Digest::SHA256.new
decoded_sig = Base64.decode64(signature)
ver = pub_key.verify(digest, decoded_sig, data)
end
which will not verify the same signature and data.
The output of
OpenSSL::Digest::SHA256.base64digest(data)
will match hashWithEncode from the Java code, but I do not understand how to pass this value to the signature verification, rather than only the SHA256 hash, as you cannot specify the base64 encoding output in the Digest object required for the verify method.
I'm building an API in Rails which decrypts one of the POST parameters using RSA. When testing encryption and decryption internally in ruby as seen below, the string literal encrypted (which seems to be UTF8 encoded) does not come out as UTF-8 after decryption. Why is it ASCII-8BIT? What's the recommended way to handle this? Should I call force_encoding("UTF-8") on the decrypted string and say in the API specification that all strings should be UTF8 before encrypting?
#rsa = OpenSSL::PKey::RSA.new(1024)
original = "hej på dig\n"
puts original.encoding.name # => "UTF-8"
ciphertext = #rsa.public_encrypt(original)
decrypted = #rsa.private_decrypt(ciphertext)
puts decrypted.encoding.name # => "ASCII-8BIT"
assert_equal original, decrypted
#expected: hej på dig
#actual: hej p\xC3\xA5 dig
I'm using Ruby 2.1.3 on OSX Yosemite with Rails 4.1.5.
Yep, you got it. You should explicitly turn the UTF-8 to bytes before encryption and back again after decryption. The underlying library simply handles unsigned chars, which are the byte equivalent for C.
If I read the Ruby API's correctly you should be able to do this by using:
string.force_encoding(Encoding::UTF_8)
I'm sending a value to the client that I want encrypted (and decrypted if/when received back).
It is not super sensitive data, I just don't want to send it in plain naked text.
I know of ActiveSupport::MessageEncryptor but it seemingly requires too many steps for my basic need. Perhaps I'm overthinking it and there's no heavy computation involved under the hood but I'm intuitively looking for something more like how setting/reading a signed cookie works.
It would be a great advantage if I wouldn't need to include anything more than what comes out of the box with Rails 4.
Why not put it in the session? Then it will be part of the encrypted cookie / in your session store.
You can set the value with session[:message] = "my message" and get it with session[:message].
Using Cipher which comes included in ruby # OpenSSL seems simple.
Try this on irb:
require "openssl"
data = "Very, very confidential data"
cipher = OpenSSL::Cipher::AES.new(128, :CBC)
cipher.encrypt
key = cipher.random_key
iv = cipher.random_iv
encrypted = cipher.update(data) + cipher.final
decipher = OpenSSL::Cipher::AES.new(128, :CBC)
decipher.decrypt
decipher.key = key
decipher.iv = iv
plain = decipher.update(encrypted) + decipher.final
puts data == plain
In order to use a third-party API, I need to encode the Net::HTTP::Post request as an MD5 hex digest, which is then used as part of the signature. However, when I try to simply Digest::MD5.hexdigest(req), it throws a "Cannot convert to string error", and when I explicitly req.to_s, it just gives the MD5 of #<Net::HTTP::Post:0x112a0eef8>
I'm simply:
request = Net::HTTP::Post.new(url.path)
request.body = {
"key" => "val"
}.to_json
# later...
hexDigest = Digest::MD5.hexdigest(request)
which is the documented spec, I think: "[with the] JSON body containing the new information."
This is the relevant sample Java code they supply:
ByteArrayOutputStream requestOutputStream = new ByteArrayOutputStream();
httpMethod.getEntity().writeTo(requestOutputStream);
DigestUtils.md5Hex(requestOutputStream.toByteArray()).toLowerCase();
Any ideas?
Thanks!
Try to call 'to_s' method explicitly, it should help:
hexDigest = Digest::MD5.hexdigest(request.to_s)
The equivalent ruby code for those lines is:
OpenSSL::Digest::MD5.hexdigest(request.body)
httpMethod.getEntity() will return the json defined as the request body.
requestOutputStream.toByteArray() will return the array of bytes corresponding to the request body.
The following function works perfect in PHP. How can it be translated in Ruby on Rails.
Please note that both privateKey and iv are 32 characters long.
mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $privateKey, base64_decode($enc), MCRYPT_MODE_CBC, $iv)
I tried to use the following in Ruby but got a bad decrypt error.
cipher = OpenSSL::Cipher.new('aes-256-cbc')
cipher.decrypt
cipher.key = privateKey
cipher.iv = iv
decrypted = '' << cipher.update(encrypted) << cipher.final
Here some code which works for me :
def decrypt_data(data, pwd, iv)
encrypted_data = Base64.decode64(data)
aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
aes.decrypt
aes.key = Digest::MD5.hexdigest(pwd)
aes.iv = iv
result = aes.update(encrypted_data) + aes.final
end
In my example the password is encrypted with MD5.
I hope this help
You are base64 decoding it in the php example. Are you doing that in the ruby one as well?
require "base64"
Base64.decode64(encrypted)
Other than that, the code looks right to me.