This may be an impossible question, but I am migrating a legacy system from Java over to PHP, and I need to be able to decrypt strings encrypted with Jasypt in PHP.
According to the documentation, Jasypt uses the following algorithm:
Append a random salt (I think that is the same as an initialization vector for the cipher) to the data to be encrypted
Encrypt repeatedly 1000 times
Prepend the unencrypted salt/IV to the encrypted string
Base64 encode the entire string
The legacy application uses the PBEWithMD5AndDES Jasypt algorithm. I am fully aware that MD5 isn't designed to be decrypted, and that's not what I'm trying to do.
I simply want to DES-decrypt the string so that all I'm left with is the MD5 hash. I can't seem to get anything but binary garbage out of PHP. What am I missing?
<?php
#jasypt.algorithm=PBEWithMD5AndDES
$secret = 'secret-password';
$encrypted = 'xh/roK2diJPDfZGlT9DlwuG2TsS7t7F+';
$cipher = MCRYPT_DES;
$modes = array(
'ecb' => MCRYPT_MODE_ECB,
'cbc' => MCRYPT_MODE_CBC,
'cfb' => MCRYPT_MODE_CFB,
'ofb' => MCRYPT_MODE_OFB,
'nofb' => MCRYPT_MODE_NOFB,
'stream' => MCRYPT_MODE_STREAM,
);
foreach($modes as $mode => $mc) {
$iv_len = 0; //mcrypt_get_iv_size($cipher, $mode);
$password = base64_decode($encrypted);
$salt = substr($password, 0, $iv_len);
$data = substr($password, $iv_len);
for($i = 0; $i < 1000; $i++) {
$data = #mcrypt_decrypt($cipher, $secret, $data, $mode, $salt);
}
var_dump("$mode: $i: $data");
}
You are not understanding the "PBEWithMD5AndDES" meaning.
PBEWithMD5AndDES means that the encryption password (a String) is hashed with MD5 in order to obtain an array of bytes used as encryption key input to the DES algorithm along with the text to be encrypted.
So, there is no way to unencrypt with DES in order to get a MD5 hash. That makes no sense. You simply need to decrypt that encrypted data using exactly that same algorithm, but in a PHP implementation.
And by the way, "PBEWithMD5AndDES" is not a "jasypt algorithm". It is a Java Cryptography Extension (JCE) algorithm. Jasypt does not implement any algorithms itself.
Hope this helps.
Php for Java simplified encryption here: https://github.com/kevwis/Phpsypt
You're missing generating the key.
I had to do the same thing for a customer of mine and wrote a few lines of code to help with issue: https://github.com/kevinsandow/PBEWithMD5AndDES
Related
I need to encrypt a string using SuiteScript, send it to a web service written in Java, and decrypt it there.
Using SuiteScript I'm able to encrypt and decrypt without any issue. But when I use the same key in java, I get different errors.
var x = "string to be encrypted";
var key = 'EB7CB21AA6FB33D3B1FF14BBE7DB4962';
var encrypted = nlapiEncrypt(x,'aes',key);
var decrypted = nlapiDecrypt(encrypted ,'aes',key);
^^works fine^^
The code in Java
final String strPassPhrase = "EB7CB21AA6FB33D3B1FF14BBE7DB4962"; //min 24 chars
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(new DESedeKeySpec(strPassPhrase.getBytes()));
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.DECRYPT_MODE, key);
String encrypted = "3764b8140ae470bda73f7ebed3c33b0895f70c3497c85f39043345128a4bc3b3";
String decrypted = new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(encrypted)));
System.out.println("Text Decryted : " + decrypted);
With the above code, I get an exception javax.crypto.BadPaddingException: Given final block not properly padded
The key was generated using openssl
openssl enc -aes-128-ecb -k mypassphrase -P
it looks like you are encrypting with AES, and decrypting with DES. I think the ciphertext needs to be decrypted with the same symmetric algorithm that you used to encrypt.
Looks like currently you have to use Suitescript to decrypt messages if it was encrypted using SuiteScript.
See suiteanswers: 35099
The workaround suggested is to use an external javascript library to encrypt/decrypt. We ended up using OpenJS on the javascript, but on the java side had to make sure the defaults were adjusted according to what is setup on the javascript side. The Java APIs were more flexible in this regard than the javascript ones.
I have a Dovecot server with MySQL database for storing usernames and passwords. The passwords in the database are in SHA512-CRYPT scheme.
I am inserting the hashed passwords in the database using a script.
doveadm pw -s SHA512-CRYPT -p password -r 500000
I want to hash the passwords using a JAVA application. I found this questions and I tried to create the same resulting hash using same password firstpassword and salt FooBarBaz. For some reason the resulting hash I get is different, although I am using the same hashing algorithm, salt and password.
Here is my Java code:
byte[] password = "firstpassword".getBytes();
byte[] salt = "FooBarBaz".getBytes();
MessageDigest digest = MessageDigest.getInstance("SHA-512");
digest.reset();
digest.update(salt);
byte[] hashed = digest.digest(password);
String encodedHash = Base64.getEncoder().encodeToString(hashed);
System.out.printf("{SHA512-CRYPT}$6$%s$%s", "FooBarBaz",encodedHash);
This outputs the hash:
{SHA512-CRYPT}$6$FooBarBaz$5WPtOnXVI/a6f003WByGKIcsfa6x0ansxiyE8uEfJ0TE5pI+Rv9kcMLgdZboKg7ZSWQgWFg+pIqruvdg6aiP/g==
I also tried swapping the order of salt + password to make it:
digest.update(password);
byte[] hashed = digest.digest(salt);
this gives me:
{SHA512-CRYPT}$6$FooBarBaz$QWS8+W5EWhModF+uO2tcsd55tDxzdzGJ5FurIbEgwVCwKfT5UqwIvBNG1Oyws8bZEFdeGgyD0u6zS1KArvGf9Q==
Does anyone have any idea how can I accomplish the same hash results in Java if I use the same password and salt?
The hash I am looking for is:
{SHA512-CRYPT}$6$FooBarBaz$.T.G.7FRJqZ6N2FF7b3BEkr5j37CWhwgvPOOoccrr0bvkBbNMmLCxzqQqKJbNhnhC.583dTBLEuZcDuQe7NEe.
doveadm uses the Unix crypt family of functions to generate the hash and outputs the hash as a Base64 encoded string. The alphabet used for the encoding (by crypt) is [a-zA-Z0-9./] (as mentioned on the man page for the functions). However, the alphabet used by the java.util.Base64 class is [A-Za-z0-9+/] (compliant with RFC 4648, as mentioned on the JavaDoc page for the Base64 class). Therefore, even if the hashed values are the same, they will get encoded differently.
A reliable option is to use the Crypt class from Apache Commons Codec as Crypt.crypt("firstpassword", "$6$FooBarBaz") (The prefix $6$ is mandatory to instruct Crypt that the SHA512-CRYPT algorithm needs to be used). This will generate your expected hash value.
We are migrating some code from perl to java/scala and we hit a roadblock.
We're trying to figure out how to do this in Java/scala:
use Crypt::CBC;
$aesKey = "some key"
$cipher = new Crypt::CBC($aesKey, "DES");
$encrypted = $cipher->encrypt("hello world");
print $encrypted // prints: Salted__�,%�8XL�/1�&�n;����쀍c
$decrypted = $cipher->decrypt($encrypted);
print $decrypted // prints: hello world
I tried a few things in scala but didn't really get it right, for example something like this:
val secretKey = new SecretKeySpec("some key".getBytes("UTF-8"), "DES")
val encipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
encipher.init(Cipher.ENCRYPT_MODE, secretKey)
val encrypted = encipher.doFinal(bytes)
println("BYTES:" + bytes)
println("ENCRYPTED!!!!!!: " + encrypted)
println(toString(encrypted))
Any help or direction in Java/scala would very much be appreciated
Assuming that Crypt module is the one I find at https://metacpan.org/pod/Crypt::CBC it is documented as by default doing (the same as) openssl, apparently meaning commandline 'enc' (openssl library has MANY other options). That is not encryption
with the specified key (and IV) directly, but instead 'password-based' encryption (PBE) with a key and IV derived from the specified 'key' (really passphrase) plus (transmitted) salt, using a twist on the original (now unrecommended) PKCS#5 v1.5 algorithm, retronymed PBKDF1. See http://www.openssl.org/docs/crypto/EVP_BytesToKey.html (or the man page on a Unix system with openssl installed) and rfc2898 (or the original RSA Labs PKCS documents now somewhere at EMC).
You say you cannot change the perl sender. I hope the users/owners/whoever realize that original DES,
retronymed single-DES for clarity, has been practically brute-forceable for well over a decade, and
PBE-1DES may be even weaker; the openssl twist doesn't iterate as PKCS#5 (both KDF1 and KDF2) should.
Java (with the Suncle providers) does implement PBEWithMD5AndDES, which initted with PBEParameterSpec (salt, 1)
does successfully decrypt data from 'openssl enc -des-cbc', and thus I expect also your perl sender (not tested).
FWIW if you could change to triple-DES, Java implements PBEWithMD5AndTripleDES using an apparently nonstandard
extension of PBKDF1 (beyond hash size) that is quite unlike openssl's nonstandard extension, and thus incompatible if the perl module is in fact following openssl.
You would have to do the key-derivation yourself and then direct 3DES-CBC-pad, which isn't very hard.
Also note encrypted data from any modern computer algorithm is binary. "Printing" it as if it were text
in perl, or Java or nearly anything else, is likely to cause data corruption if you try to use it again.
If you are only looking to see 'is there any output at all, and is it visibly not the plaintext' you're okay.
I have been tasked with replacing a legacy java system with something which runs PHP.
I am getting a little stuck on replacing the java cryptography with PHP code.
cipherAlgorythm = "PBEWithMD5AndDES";
cipherTransformation = "PBEWithMD5AndDES/CBC/PKCS5Padding";
PBEParameterSpec ps = new javax.crypto.spec.PBEParameterSpec(salt, iterations);
SecretKeyFactory kf = SecretKeyFactory.getInstance(cipherAlgorythm);
SecretKey key = kf.generateSecret(new javax.crypto.spec.PBEKeySpec(password.toCharArray()));
Cipher encryptCipher = Cipher.getInstance(cipherTransformation);
encryptCipher.init(Cipher.ENCRYPT_MODE, key, ps);
byte[] output = encryptCipher.doFinal("This is a test string".getBytes("UTF-8"));
Seems to be the guts of the Java
In PHP I am doing
$hashed_key = pbkdf2('md5', $this->key, $this->salt, $this->reps , <GUESS 1>, TRUE);
$output = mcrypt_encrypt(MCRYPT_DES, $hashed_key, "This is a test string", MCRYPT_MODE_CBC, <GUESS 2>);
pbkdf2 is from here.
So <GUESS 1> is the key size and <GUESS 2> is the IV. I have played around with these to no avail. Does anyone have suggestion for such values? As far as I can see the encryption itself should be portable but I am unsure about what is going on in some of the Java methods.
It looks like java is creating an IV somewhere, but I don't understand how or where.
RELATED
Decrypt ( with PHP ) a Java encryption ( PBEWithMD5AndDES )
You may want to look at http://us3.php.net/manual/en/ref.mcrypt.php#69782, but basically he implemented a DIY padding solution:
function pkcs5_pad ($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
That may be your best bet, but if you look at this comment, his suggestions on how to verify that each step is correct may be useful for you.
https://stackoverflow.com/a/10201034/67566
Ideally you should move away from DES and since this padding is going to be a problem in PHP, why not see if you can change the encryption algorithm to something less troublesome and more secure?
To help you can show this page: http://www.ietf.org/rfc/rfc4772.txt, where it is succinctly expressed that DES is susceptible to brute force attacks, so has been deprecated and replaced with AES.
Both existing answers helped, but I'll post the complete solution here.
I have not seen it documented anywhere but after looking at implementations for this encryption scheme I found the key is the first 8 bytes of the encrypted hash and the IV is the last 8.
public function get_key_and_iv($key, $salt, $reps) {
$hash = $key . $salt;
for ($i = 0; $i< $reps; $i++) {
$hash = md5($hash, TRUE);
}
return str_split($hash,8);
}
seems to do the trick. Which replaces pbkdf2 in my question, negates the need for <GUESS 1> and gives a value for <GUESS 2>
Then I got caught with the padding problem which James Black mentioned and managed to fix. So final code is
list($hashed_key, $iv) = get_key_and_iv($key, $salt, $reps);
// 8 is DES block size.
$pad = 8 - (strlen($plaintext) % 8);
$padded_string = $plaintext . str_repeat(chr($pad), $pad);
return mcrypt_encrypt(MCRYPT_DES, $hashed_key, $padded_string, MCRYPT_MODE_CBC, $iv);
You can use hash_pbkdf2 PHP (5.5) function too instead of using PBKDF2 PHP libraries.
According to PHP docs the GUESS 1 is the length of the created derived key
length
The length of the output string. If raw_output is TRUE this corresponds to the
byte-length of the derived key, if raw_output is
FALSE this corresponds to twice the byte-length of the derived key (as
every byte of the key is returned as two hexits).
If 0 is passed, the entire output of the supplied algorithm is used.
Maybe this post (what is an optimal Hash size in bytes?) result interesting for you.
GUESS 2 or IV is a random initialization vector used to create an unique salt to generate the hash.
You can create the IV with mycript_create_iv function.
Take a look at the complete sample in PHP.net
<?php
$password = "password";
$iterations = 1000;
// Generate a random IV using mcrypt_create_iv(),
// openssl_random_pseudo_bytes() or another suitable source of randomness
$salt = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$hash = hash_pbkdf2("sha256", $password, $salt, $iterations, 20);
echo $hash;
?>
Is there an easy way in Java to generate password hashes in same form as generated by "openssl passwd -1".
Example:
# openssl passwd -1 test
$1$Gt24/BL6$E4ZsrluohHFxtcdqCH7jo.
I'm looking for a pure java solution that does not call openssl or any other external program.
Thanks
Raffael
The openssl docs describe the -1 option as: "Use the MD5 based BSD password algorithm 1."
Jasypt is a java cryptogrqphy library, as is jBCrypt. Jasypt is slightly more complicated, but more configurable.
I don't know that much about crypto, but my guess is that the password generated by openssl breaks down as:
$1$ - specifies that this was generated using the MD5 scheme
Gt24/BL6 - 8 byte salt
$ - delimiter
E4ZsrluohHFxtcdqCH7jo. - hash
so it looks like Jasypt's BasicPasswordEncryptor might be what you want-
Perhaps something like this?
MessageDigest md = null;
md = MessageDigest.getInstance("SHA");
md.update(pPassword.getBytes("UTF-8"));
byte raw[] = md.digest();
String hash = BASE64Encoder.encodeBuffer(raw);
The Java BASE64Encoder source can be found on the net.
You can find source code for the C language version here. It should be straightforward to convert it to pure Java.