Can't decrypt Ruby encrypted string in Scala - ruby

I'm using ActiveSupport::MessageEncryptor to encrypt a string in Ruby as follows:
salt = SecureRandom.random_bytes(64)
// => "s\x90L\xB8\xEF\x8BBp\xB6\xF5A\x95\xA8]+\x94\xF3\xA7\x9A\x84+jC\xBF\xB0\x15\xEF*\x8C\xDD.\xE5\xC7Y\xCE\xE1\xAA\xA4I/%.\x9E\x14\xC1\xA8\x9E\x122\xE0\x19.\x19\xD8\xB6\xE8\x83\xE1\xFE\x16\xB5\x11N\x18"
key = ActiveSupport::KeyGenerator.new('password').generate_key(salt)
// => "\x12\xBD1\xA0Q\xBF)\\\x89\xDF\x95\xD0\f\x03\x17P'\x87\xAD\x92b\xB5%\xC7X\x01\x9Ar\xCB\xC9\x1A\x10'\xC4\x95w\xBF\xED]\x17\xEB\x9F#\xC6\xEE8S\xE1^\x18\xE2^\x85Z\rJ\x9A\xEE\xA5\xEC|\xA2\xA9\x8E"
crypt = ActiveSupport::MessageEncryptor.new(key)
encrypted_username = crypt.encrypt_and_sign("daniel")
// => "N0dHcFM3MnQrcW1HUk9UTGwxeUJsZmlCNzcwUGhrdUdtbE9YWnUxamZFST0tLUVUcUlIU2k1ZHIvTmlDRUgzM2FsS0E9PQ==--1ede80eb2b498ddf5133f8f3a45a82db2476c740"
Then in Scala I'm trying to decrypt like so:
var encrypted_str = "N0dHcFM3MnQrcW1HUk9UTGwxeUJsZmlCNzcwUGhrdUdtbE9YWnUxamZFST0tLUVUcUlIU2k1ZHIvTmlDRUgzM2FsS0E9PQ==--1ede80eb2b498ddf5133f8f3a45a82db2476c740"
val parts = encrypted_str.split("--");
val encryptedData = Base64.decodeBase64(parts(0))
val iv = Base64.decodeBase64(parts(1))
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(iv.take(16)));
val result = cipher.doFinal(encryptedData);
println(new String(result, "UTF-8"))
But I run into this error:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher

I think the problem might be here:
val iv = Base64.decodeBase64(parts(1))
The second part of your message is 1ede80eb2b498ddf5133f8f3a45a82db2476c740 which is not a base 64 encoded string, it's a hex encoded string. Try this instead:
Hex.decodeHex(parts(1))

Related

How to decrypt of AES-256-GCM created with ruby in sjcl.js

I'm trying to decrypt an AES cipher generated by Ruby with the sjcl.js library.
I'm getting a "corrupt" error for an unknown reason……. I want to fix the problem.
For reference, when encryption and decryption were attempted in CBC mode, decryption was successful.
Ruby Code:
cipher = OpenSSL::Cipher.new('aes-256-gcm')
cipher.encrypt
iv = cipher.random_iv
cipher.key = Digest::SHA256.digest(password)
ciphertext = cipher.update(plaintext) + cipher.final
return Base64.strict_encode64(iv) + Base64.strict_encode64(ciphertext)
Javascript Code:
var iv = sjcl.codec.base64.toBits(IV_BASE64);
var ciphertext = sjcl.codec.base64.toBits(CIPHERTEXT_BASE64);
var key = sjcl.hash.sha256.hash(KEY_UTF8);
var decrypted = sjcl.mode.gcm.decrypt(new sjcl.cipher.aes(key), ciphertext, iv);
AES-GCM is an authenticated encryption algorithm. It automatically generates an authentication tag during encryption, which is used for authentication during decryption. This tag is not considered in the current Ruby code. It is 16 bytes by default, can be retrieved with cipher.auth_tag and must be added, e.g.:
ciphertext = cipher.update(plaintext) + cipher.final + cipher.auth_tag
Regarding nonce/IV, note that Base64 encoding should actually be done after concatenation (which, however, is not critical for a 12 bytes nonce/IV commonly used with GCM).
On the JavaScript side the separation of the nonce/IV is missing. Ciphertext and tag do not need to be separated because the sjcl processes the concatenation of both (ciphertext|tag):
const GCM_NONCE_LENGTH = 12 * 8
const GCM_TAG_LENGTH = 16 * 8
// Separate IV and ciptertext/tag combination
let ivCiphertextTagB64 = "2wLsVLuOJFX1pfwwjoLhQrW7f/86AefyZ7FwJEhJVIpU+iG2EITzushCpDRxgqK2cwVYvfNt7KFZ39obMMmIqhrDCIeifzs="
let ivCiphertextTag = sjcl.codec.base64.toBits(ivCiphertextTagB64)
let iv = sjcl.bitArray.bitSlice(ivCiphertextTag, 0, GCM_NONCE_LENGTH)
let ciphertextTag = sjcl.bitArray.bitSlice(ivCiphertextTag, GCM_NONCE_LENGTH)
// Derive key via SHA256
let key = sjcl.hash.sha256.hash("my password")
// Decrypt
let cipher = new sjcl.cipher.aes(key)
let plaintext = sjcl.mode.gcm.decrypt(cipher, ciphertextTag, iv, null, GCM_TAG_LENGTH)
//let plaintext = sjcl.mode.gcm.decrypt(cipher, ciphertextTag, iv) // works also; here the defaults for the AAD ([]) and the tag size (16 bytes) are applied
console.log(sjcl.codec.utf8String.fromBits(plaintext))
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/sjcl/1.0.8/sjcl.min.js "></script>
The ciphertext used in the above code was generated with the Ruby code considering the authentication tag and is successfully decrypted.
Note that key derivation with a digest is insecure. Instead, a reliable key derivation function like PBKDF2 should be used.

How to Hash Value in Flutter Using SHA256?

Hashing Value (String or Int OR etc...) in Flutter ## Heading ##
I have Value like "Almahery"
How to Hash in in SHA 256 ?
Import (Crypto) :
import 'package:crypto/crypto.dart';
Then add this code:
var bytes1 = utf8.encode("Almahery"); // data being hashed
var digest1 = sha256.convert(bytes1); // Hashing Process
print("Digest as bytes: ${digest1.bytes}"); // Print Bytes
print("Digest as hex string: $digest1"); // Print After Hashing
let you want convert apple to SHA256 String
import 'package:crypto/crypto.dart';
var appleInBytes = utf8.encode("apple");
String value = sha256.convert(appleInBytes);
print(value.toString());
|
|
\|/
result
===> "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b"

Convert a binary string (SecureRandom.random_bytes) into a hexadecimal string?

I'm generating a 32 byte key and 16 byte iv for my AES-256 CBC Ruby encryption implementation:
key = SecureRandom.random_bytes(32) # => "m\xD4\x90\x85\xF9\xCD\x13\x98\xAB\v\xBB\xCD\x0E\x17\xFAA\xF9\x99\xAF\e\x8A\xB5\x8Ate\x93[m\x9As\xC7\xCB"
iv = SecureRandom.random_bytes(16) # => "\xDF\x95[\xD5\xDD(\x0F\xB8SE\xFCZr\xF1\xB1W"
ruby_cipher = SymmetricEncryption::Cipher.new(
key: key,
iv: iv,
cipher_name: 'aes-256-cbc'
)
ruby_cipher.encrypt("Hello!") # => 'qAnTLy7jyiLRkUqBnME8sw=='
Question:
How do I convert the key and iv to a hexadecimal string, so I can transport them to the other applications?
Context:
In another application, that uses Javascript via CryptoJS I need to receive the key and iv and convert them back to bytes like this:
CryptoJS.AES.encrypt(
"Hello!",
CryptoJS.enc.Utf8.parse(key),
{ iv: CryptoJS.enc.Utf8.parse(iv) }
).toString() // 'qAnTLy7jyiLRkUqBnME8sw=='
In a third PHP application I will use the Hex strings directly like this:
<?php
openssl_encrypt(
'Hello!', 'aes-256-cbc',
key,
0,
iv
); // => 'qAnTLy7jyiLRkUqBnME8sw=='
I think this should do the job:
key = SecureRandom.random_bytes(32)
key_as_str = key.each_byte.map{ |byte| '%02x' % byte }.join
I did verify this solution with the following scripts:
test.rb
require 'securerandom'
require 'symmetric-encryption'
key = SecureRandom.random_bytes(32)
iv = SecureRandom.random_bytes(16)
ruby_cipher = SymmetricEncryption::Cipher.new(
key: key,
iv: iv,
cipher_name: 'aes-256-cbc'
)
hex_key = key.each_byte.map{ |byte| '%02x' % byte }.join
hex_iv = iv.each_byte.map{ |byte| '%02x' % byte }.join
encoded = ruby_cipher.encrypt("Hello!")
puts "Ruby encoded: #{encoded}"
system("php test.php #{hex_key} #{hex_iv}")
test.php
<?php
$encoded = openssl_encrypt(
'Hello!', 'aes-256-cbc',
hex2bin($argv[1]),
0,
hex2bin($argv[2])
);
print "php encoded: $encoded\n";
looks the same on my machine.
You could do it the same way SecureRandom does for their #hex method:
key = SecureRandom.random_bytes(32)
key_as_hex = key.unpack('H*')[0]
(Using a single-quoted string works fine here for this non-interpolated string, and is rubocop friendly.)

Encrypt password with PBEWithMD5AndDES and fetch data from DB gives a blank response

This is my code
def encrypt(q,_userEmail,password):
"""Mimic Java's PBEWithMD5AndDES algorithm to produce a DES key"""
_password = '111'
_salt = '\xA9\x9B\xC8\x32\x56\x35\xE3\x03'
_iterations = 19
plaintext_to_encrypt = password
hasher = MD5.new()
hasher.update(_password)
hasher.update(_salt)
result = hasher.digest()
for i in range(1, _iterations):
hasher = MD5.new()
hasher.update(result)
result = hasher.digest()
# Pad plaintext per RFC 2898 Section 6.1
padding = 8 - len(plaintext_to_encrypt) % 8
plaintext_to_encrypt += chr(padding) * padding
encoder = DES.new(result[:8], DES.MODE_CBC, result[8:16])
encrypted = encoder.encrypt(plaintext_to_encrypt)
q.put(encrypted.encode('base64'))
pw = encrypted.encode('base64')
print str(pw)
cur = db.cursor()
cur.execute('''SELECT * FROM UTTARA_USER_MAST WHERE EMAIL_ID=:1 AND PASSWD=:2''',(_userEmail,str(pw),))
data=cur.fetchall()
print data
print str(pw) prints the encrypted password ,when i pass pw in a query
the query returns blank but when i give the encrypted string directly in query it returns the data
edit: I use Oracle DB

Concatenate variables and create MD5

Using JMeter, I would like to take values from CSV file, concatenate the values and do a MD5 hash on them and then send the value as part of HTTP request using HTTP Request Sampler.
I tried the following but did not get the correct result:
created CSV Data Set Config and added the variables csvVal1,csvVal2,csvVal3;
in the jp#gc-Dummy Sampler i added the following:
${__MD5(${csvval1}+${csvval2}+${csvval3})}
This did not work, what is the right way?
I ended up using BeanShell Preporcessor and used the following script
import java.security.MessageDigest;
String val1 = vars.get("csv_val1");
String val2 = vars.get("csv_val2");
String val3 = vars.get("csv_val3");
String totalString = val1+val2+val3;
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5hash = new byte[32];
md.update(totalString.getBytes("utf-8"), 0, totalString.length());
md5hash = md.digest();
StringBuffer sb = new StringBuffer();
for (int i=0;i<md5hash.length;i++) {
String sval = Integer.toHexString((int) md5hash[i] & 0xFF);
if(sval.length()== 1)
{
sval = "0"+sval;
}
sb.append(sval);
}
log.info("tktest: "+ sb);
vars.putObject("MD5Signature", sb.toString());
There's a new function __digest, currently in nightly builds
In your case to save in MD5Signature variable the result of 3 variable use the following:
${__digest(MD5,${csv_val1}${csv_val2}${csv_val3},,,MD5Signature)}

Resources