Why does OpenSSL not return the same values using public_key.verify and private_key.private_encrypt(digest) - ruby

As far as I understand, signing data with an asymmetric key pair is essentially the same as using the private key to encrypt that same data. It says as much here: http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL.html. Ruby openssl seems to use an approach of hashing the data first then signing it. So I am confused why the value of signature is not equivalent at the end of both operations:
1.
data = 'Sign me!'
digest = OpenSSL::Digest::SHA256.new
pkey = OpenSSL::PKey::RSA.new(2048)
signature = pkey.sign(digest, data)
puts signature
2.
data = 'Sign me!'
data_hash = OpenSSL::Digest::digest("SHA256", data)
signature = pkey.private_encrypt(data_hash.to_s)
puts signature
(or if the digest is not working as I thought)
3.
data = 'Sign me!'
signature = pkey.private_encrypt(data)
puts signature
I am guessing that there are formatting things going on in the background. Now, this is for academic understanding, I will use verify for actual signature verification.

Related

OLA Money API Hash Code Error

While integrating OLA Money API, when I hit url with all parameter am getting error
"Hash Code mismatched"
The main problem is when we send generated hash code through url, then last 2 characters of hash key == are changed into %3D%3D. Could you please give me solution of this.
Both Hash key are given below:
Generated Hash Key before URL-------------------------------------------------------------------------
eyJjb21tYW5kIjoiZGViaXQiLCJhY2Nlc3NUb2tlbiI6IjN1NDFwODJ1VDEiLCJ1bmlxdWVJZCI6IjEyMzQ1Nk9MNTY0Nzg4OSIsImNvbW1lbnRzIjoib2RldFgiLCJ1ZGYiOiI4dkJkZiIsImhhc2giOiJjODkzZTFjMWViZTQ1MTliMTUzOGE1NTEyNTUzMzRjNGRlNjZiNWRiNDQ4OWI1MTdlN2MxN2RhYzM4YWMwNTA3MGY1ZDQ3MDBiNjRlMTUyMTUyYzg5NWVlYzFhMDYyMGYzMTFlNzkyMDYzNzk5OThjZDQ2ZGE0ZDkxMzRiYzEzZSIsInJldHVyblVybCI6Imh0dHA6Ly93d3cucnVwbGVlZGV2bG9wbWVudC5jb20vc2VydmljZS93ZWJzZXJ2aWNlc192MDMvb2xhbW9uZXkvb2xhUmVzcG9uc2UucGhwIiwibm90aWZpY2F0aW9uVXJsIjoiaHR0cDovL3d3dy5ydXBsZWVkZXZsb3BtZW50LmNvbS9zZXJ2aWNlL3dlYnNlcnZpY2VzX3YwMy9vbGFtb25leS9vbGFOb3RpZnkucGhwIiwiYW1vdW50IjoxLCJjdXJyZW5jeSI6IklOUiIsImNvdXBvbkNvZGUiOiIifQ==
Generated Hash Key in URL--------------------------------------------------------------------------------
eyJjb21tYW5kIjoiZGViaXQiLCJhY2Nlc3NUb2tlbiI6IjN1NDFwODJ1VDEiLCJ1bmlxdWVJZCI6IjEyMzQ1Nk9MNTY0Nzg4OSIsImNvbW1lbnRzIjoib2RldFgiLCJ1ZGYiOiI4dkJkZiIsImhhc2giOiJjODkzZTFjMWViZTQ1MTliMTUzOGE1NTEyNTUzMzRjNGRlNjZiNWRiNDQ4OWI1MTdlN2MxN2RhYzM4YWMwNTA3MGY1ZDQ3MDBiNjRlMTUyMTUyYzg5NWVlYzFhMDYyMGYzMTFlNzkyMDYzNzk5OThjZDQ2ZGE0ZDkxMzRiYzEzZSIsInJldHVyblVybCI6Imh0dHA6Ly93d3cucnVwbGVlZGV2bG9wbWVudC5jb20vc2VydmljZS93ZWJzZXJ2aWNlc192MDMvb2xhbW9uZXkvb2xhUmVzcG9uc2UucGhwIiwibm90aWZpY2F0aW9uVXJsIjoiaHR0cDovL3d3dy5ydXBsZWVkZXZsb3BtZW50LmNvbS9zZXJ2aWNlL3dlYnNlcnZpY2VzX3YwMy9vbGFtb25leS9vbGFOb3RpZnkucGhwIiwiYW1vdW50IjoxLCJjdXJyZW5jeSI6IklOUiIsImNvdXBvbkNvZGUiOiIifQ%3D%3D
I look forward to solution from you,
Issue here is - one of the Hash is getting URL encoded. Easiest way is to URL decode both the strings and then match. Here:
require 'uri'
h1 = "eyJjb21tYW5kIjoiZGViaXQiLCJhY2Nlc3NUb2tlbiI6IjN1NDFwODJ1VDEiLCJ1bmlxdWVJZCI6IjEyMzQ1Nk9MNTY0Nzg4OSIsImNvbW1lbnRzIjoib2RldFgiLCJ1ZGYiOiI4dkJkZiIsImhhc2giOiJjODkzZTFjMWViZTQ1MTliMTUzOGE1NTEyNTUzMzRjNGRlNjZiNWRiNDQ4OWI1MTdlN2MxN2RhYzM4YWMwNTA3MGY1ZDQ3MDBiNjRlMTUyMTUyYzg5NWVlYzFhMDYyMGYzMTFlNzkyMDYzNzk5OThjZDQ2ZGE0ZDkxMzRiYzEzZSIsInJldHVyblVybCI6Imh0dHA6Ly93d3cucnVwbGVlZGV2bG9wbWVudC5jb20vc2VydmljZS93ZWJzZXJ2aWNlc192MDMvb2xhbW9uZXkvb2xhUmVzcG9uc2UucGhwIiwibm90aWZpY2F0aW9uVXJsIjoiaHR0cDovL3d3dy5ydXBsZWVkZXZsb3BtZW50LmNvbS9zZXJ2aWNlL3dlYnNlcnZpY2VzX3YwMy9vbGFtb25leS9vbGFOb3RpZnkucGhwIiwiYW1vdW50IjoxLCJjdXJyZW5jeSI6IklOUiIsImNvdXBvbkNvZGUiOiIifQ=="
h2 = "eyJjb21tYW5kIjoiZGViaXQiLCJhY2Nlc3NUb2tlbiI6IjN1NDFwODJ1VDEiLCJ1bmlxdWVJZCI6IjEyMzQ1Nk9MNTY0Nzg4OSIsImNvbW1lbnRzIjoib2RldFgiLCJ1ZGYiOiI4dkJkZiIsImhhc2giOiJjODkzZTFjMWViZTQ1MTliMTUzOGE1NTEyNTUzMzRjNGRlNjZiNWRiNDQ4OWI1MTdlN2MxN2RhYzM4YWMwNTA3MGY1ZDQ3MDBiNjRlMTUyMTUyYzg5NWVlYzFhMDYyMGYzMTFlNzkyMDYzNzk5OThjZDQ2ZGE0ZDkxMzRiYzEzZSIsInJldHVyblVybCI6Imh0dHA6Ly93d3cucnVwbGVlZGV2bG9wbWVudC5jb20vc2VydmljZS93ZWJzZXJ2aWNlc192MDMvb2xhbW9uZXkvb2xhUmVzcG9uc2UucGhwIiwibm90aWZpY2F0aW9uVXJsIjoiaHR0cDovL3d3dy5ydXBsZWVkZXZsb3BtZW50LmNvbS9zZXJ2aWNlL3dlYnNlcnZpY2VzX3YwMy9vbGFtb25leS9vbGFOb3RpZnkucGhwIiwiYW1vdW50IjoxLCJjdXJyZW5jeSI6IklOUiIsImNvdXBvbkNvZGUiOiIifQ%3D%3D"
h1 == h2
# => false
URI.unescape(h1) == URI.unescape(h2)
# => true

What is the role of SHA hash in signing a document in OpenSSL library?

I am following OpenSSL directives to generate signatures. I am using ruby 2.1.0 and am generating signatures like this:
document = "This is a simple string document to be signed"
key = OpenSSL::PKey::RSA.new([private_key])
digest = OpenSSL::Digest::SHA256.new
signature = key.sign digest, document
The signature is transmitted and reaches the destination where it is to be verified. To verify, I do like this:
key = OpenSSL::PKey::RSA.new([pubkey])
digest = OpenSSL::Digest::SHA256.new
key.verify digest, signature, document # => valid
This is working because if we change just one letter of the document or signature, this returns invalid result:
key.verify digest, signature, changed_document # => Invalid
But with a different SHA, the verification command still results in a valid result:
digest = OpenSSL::Digest::SHA256.new('this will generate different SHA')
key.verify digest, signature, document # => valid
It confused me. Shouldn't a different SHA hash result in invalid result? What is the role of digest here?
Passing an argument to OpenSSL::Digest::SHA256.new causes that data to be added to the digest.
However, the openssl signing functions reset the digest before it is used and so that extra data has no effect in this particular case.

Password salt and PBKDF2

I'm looking into different solutions regarding storing passwords in Database. After reading a lot I think i will end up with PBKDF2.
Although I'm a little bit confused regarding if I should input salt to my PBKDF2 function and store the salt in a column and the PBKDF2'd password in another column.
I'm also using CodeIgniter and found a library for PBKDF2 (https://github.com/HashemQolami/CodeIgniter-PBKDF2-Library) Which claims I don't need to store the salt separately.
Register user by using $pbkdf2['hash'] as user's password which has
been recommended; no need to store user's salt separately.
https://github.com/HashemQolami/CodeIgniter-PBKDF2-Library#step-2
So if I'm assuming correct all I need is to provide a password into the function and the function take care of the rest?
I'm the creator of CodeIgniter PBKDF2 Library. Just found this topic on SO, and I decide to clarify how this library works.
Here is the sample code from the doc:
# Load pbkdf2 library into your controller
$this->load->library('pbkdf2');
# Get password, which has been sent via POST method
$password = $this->input->post('password');
# Encrypt the given password using a random generated salt
$pbkdf2 = $this->pbkdf2->encrypt($password);
The encrypt() method, returns an array which has 3 keys: salt, password, hash.
The value of hash is the concatenation of salt and password.
This feature lets the user to choose how to use this library, whether to work with salt and password or hash (salt + password).
The syntax of encrypt() method:
encrypt( string $password [, mixed $good_hash = NULL [, bool $object_output = FALSE]] )
The function uses the given $good_hash as the salt to generate the encrypted password. And it uses a random generated salt if the $good_hash parameter is not given.
So, If you have stored the salt separately, you could pass it to the function as the second parameter to encrypt the given password:
$pbkdf2 = $this->pbkdf2->encrypt($password, $salt);
On the other hand, If you have stored the concatenation of salt and password into database, you could pass that to the function as the second parameter, too:
$pbkdf2 = $this->pbkdf2->encrypt($password, $hash);
The function will break the given $hash automatically to fetch the salt.
So, you could store the concatenation of salt and password in a column (64 characters by default) and then encrypt the new given password by using old stored one.
Putting all together
In the following, I'll show you how to work with this library to register/login the user, without storing the salt and the password separately.
Registering the user:
$this->load->library('pbkdf2');
$password = $this->input->post('password');
$pbkdf2 = $this->pbkdf2->encrypt($password);
# Store $pbkdf2['hash'] into User table as the user's password
Logging in the user:
$this->load->library('pbkdf2');
$username = $this->input->post('username', TRUE);
$password = $this->input->post('password');
# Fetch the stored user's password from the database
$user_password = $this->user_model->get_password_by($username);
# Check whether the User exists
if ($user_password)
{
# Encrypt the new given password by using the old one:
$pbkdf2 = $this->pbkdf2->encrypt($password, $user_password);
# Check whether the new generated password matches the old one
if ($pbkdf2['hash'] === $user_password) {
# Log in the user ...
} else {
# Show an error...
}
} else {
# Show an error...
}

Not able to Decrypt string using RSA.rb: RSA Encryption for Ruby

I have to encrypt a particular field value and store in DB. I have used RSA Encryption for Ruby. I was able to encrypt and save it, but then while decrypting it back, i am facing problem. What i have done is as follows,
key_pair = RSA::KeyPair.generate(512)
Stored key_pair in separate column.
ciphertext = key_pair.encrypt("Hello, world!")
Stored ciphertext in another column in same table.
While decrypting, i fetched the key_pair value from database and applied decrypting function
plaintext = key_pair.decrypt(ciphertext)
This step throws error
NoMethodError: undefined method `decrypt' for <String:0xa431b88>
because "key_pair" is not an instance of "RSA::KeyPair".
When i try to decrypt the stored value, i fetch key_pair value from database and then apply decrypt method on it. So the key_pair value has String class. I need a way to solve. Please guide me.
Before decrypt, try:
# get persisted value from DB; then
key_pair = RSA::KeyPair.new(your private key, your public key)
# and then decrypt
plaintext = key_pair.decrypt(ciphertext)

Getting as3crypto to work with ruby (Gibberish/EzCrypto)

I'm trying to get as3crypto to play nice with either Gibberish or EzCrypto in AES-128 mode.
No matter what combination of settings I use I simply cannot get one to decrypt the other, and usually get a "bad decrypt" message in ruby. Each contained environment can decrypt data it encrypted itself but one cannot seem to decrypt the other.
Has anyone been able to get the two to work together?
Here's one of the variations I tried:
On the Actionscript side, using as3crypto:
//define the encryption key
var key:ByteArray = Hex.toArray("password");
//put plaintext into a bytearray
var plainText:ByteArray = Hex.toArray(Hex.fromString("this is a secret!"));
//set the encryption key
var aes:AESKey = new AESKey(key);
//encrypt the text
aes.encrypt( plainText );
trace(Base64.encode(Hex.fromArray(plainText)));
//encrypted value is N2QwZmI0YWQ4NzhmNDNhYjYzM2QxMTAwNGYzNDI1ZGUyMQ==
And on the ruby side, using gibberish:
// also tried the default size (256)
cipher = Gibberish::AES.new("password",128)
// raises the following exception: OpenSSL::Cipher::CipherError: wrong final block length
cipher.dec("N2QwZmI0YWQ4NzhmNDNhYjYzM2QxMTAwNGYzNDI1ZGUyMQ==")
I've tried all sort of different approaches, all yielding either the above exception or "bad encrypt"
Finally figured it out myself. The thing is both Gibberish and EzCrypto do not seem to provide a way to specify an IV, which is needed when using aes-cbc. The trick is to extract the iv from the first 16 bytes of the encrypted data as3crypto produces.
Here's the as3 code, which also changed a little:
// there are other ways to create the key, but this works well
var key:ByteArray = new ByteArray();
key.writeUTFBytes(MD5.encrypt("password"));
// encrypt the data. simple-aes-cbc is equiv. to aes-256-cbc in openssl/ruby, if your key is
// long enough (an MD5 is 32 bytes long)
var data:ByteArray = Hex.toArray(Hex.fromString("secret"));
var mode:ICipher= Crypto.getCipher("simple-aes-cbc", key) ;
mode.encrypt(data);
// the value here is base64, 32 bytes long. the first 16 bytes are the IV, needed to decrypt
// the data in ruby
// e.g: sEFOIF57LVGC+HMEI9EMTpcJdcu4J3qJm0PDdHE/OSY=
trace(Base64.encodeByteArray(data));
The ruby part uses a gem called encryptor to supply the iv.
you can also use OpenSSL directly, it's pretty straight forward:
key = Digest::MD5.hexdigest("password")
// decode the base64 encoded data back to binary:
encrypted_data = Base64.decode64("sEFOIF57LVGC+HMEI9EMTpcJdcu4J3qJm0PDdHE/OSY=")
// the tricky part: extract the IV from the decoded data
iv = encrypted_data.slice!(0,16)
// decrypt!
Encryptor.decrypt(encrypted_data,:key=>key,:iv=>iv)
// should output "secret"

Resources