I am migrating my PHP code to Google App Engine - Java.
So I need an equivalent of PHP's crypt function in Java,
since I have stored all the passwords of registered users
using crypt in my DB.
Edit 1:
Here is my php code for encrypting passwords :
$password = "test123";
$pwd = crypt($password,$password);
echo $pwd;
Output is (On Windows as well as a linux based server on HostMonser):
temjCCsjBECmU
Can someone give me equivalted java code?
I have tried various permutations & combinations with
MessageDigest class, but can't get it right..
Edit 2:
Here is sample code which I thought would work but did not:
try {
{
String password = "test123";
MessageDigest digest = MessageDigest.getInstance( "MD5" );
byte[] passwordBytes = password.getBytes( );
digest.reset( );
digest.update( passwordBytes );
digest.update( passwordBytes );
byte[] message = digest.digest( );
StringBuffer hexString = new StringBuffer();
for ( int i=0; i < message.length; i++)
{
hexString.append( Integer.toHexString(
0xFF & message[ i ] ) );
}
String encrypted = hexString.toString();
System.out.println(encrypted);
} } catch (NoSuchAlgorithmException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
This is an old thread but I ran into the same issue and found a different solution. You can use the UnixCrypt/Md5Crypt classes in the Apache Commons Codec 1.7 library.
For example you can call
UnixCrypt.crypt(string, salt)
OR
Md5Crypt.md5Crypt(byte[], salt)
I haven't looked into the other encryption types but I imagine their are other utilities as well.
org.apache.commons.codec.digest.UnixCrypt
org.apache.commons.codec.digest.Md5Crypt
You have to know what implementation of PHP crypt has been used (MD5? SHA256? SHA512?) because there are several, depending on your OS : http://php.net/manual/fr/function.crypt.php
The Java equivalent class is MessageDigest. When you create an instance of this class, you provide the hash algorithm, for example :
MessageDigest md = MessageDigest.getInstance("MD5");
MessageDigest md2 = MessageDigest.getInstance("SHA-256");
MessageDigest md3 = MessageDigest.getInstance("SHA-512");
// etc.
byte[] encryptedPassword = md.digest("yourPassword".getBytes());
It seems you have to work with a legacy database already populated with passwords you cannot discard, so you can't just switch to a salted MessageDigest, preferably using SHA-1. And your problem gets more complicated, since PHP's crypt is a wrapper that might use one of several algorithms. But let's assume your PHP uses the original DES-based UNIX crypt, then all you need is an implementation of that in Java. As far as i know, there is no implementation of UNIX's crypt in the standard Java installation, but you might want to look here for a list of options.
You need to take a look at the java.security classes (what used to tbe the JCE):
In there you'll find everything you need to do what you want (depending on which algorithm you need).
http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/security/package-summary.html
e.g. MessageDigest for MD5/SHA etc:
http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/security/MessageDigest.html
Check these against the Google App Engine whitelist here, I'm not sure what's supported and what isn't.
http://code.google.com/appengine/docs/java/jrewhitelist.html
The java.security stuff can be a bit of a pain to work with sometimes, you may alternatively want to use Jasypt - which is a more simplified API that works with any JCE:
http://www.jasypt.org/
PHP's crypt supports multiple hash functions. If you use the MD5 version (hash starts with $1$), you can find a Java implementation here,
http://www.java2s.com/Open-Source/Java-Document/Groupware/LibreSource/md5/MD5Crypt.java.htm
Please notice that they use their own MD5 class. I am not sure if it's the same as standard MD5.
I am sure you can find Java implementation for other hash algorithms too.
Well, PHP's crypt isn't actually encryption as far as I know. It's just a wrapper around some one-way hashing functions I believe, so if your current PHP site's using crypt's MD5 or SHA256 or whatever, I'd expect that you could find those equivalent hashing classes/functions in Java.
I can recommend this: MD5Crypt implementation
MD5Crypt.crypt("youPassword"); // output: $1$zSiw0koU$i3Srfmoxx4VPePJHWqAuK/
This is one of the few implementations, which works for me.
Related
I'm trying to send requests to API. Api docs provide examples for salt and sign that should be present in request body.
PHP example:
$sign_key = 'testString';
$salt = sha1('testKey');
$sign = hash_hmac('sha512', $salt, $sign_key);
My java code is:
String salt = DigestUtils.sha1Hex("testKey");
SecretKeySpec secretKeySpec = new SecretKeySpec(salt.getBytes(StandardCharsets.UTF_8),
"HmacSHA512");
Mac mac = Mac.getInstance("HmacSHA512");
mac.init(secretKeySpec);
String sign = Hex.encodeHexString(mac.doFinal("testString".getBytes(StandardCharsets.UTF_8)));
Salt calculated on php and java matches, but sign differ.
I've checked some posts like following:
Java HmacSHA512
php base64_encode hash_hmac and java gives different results
Compute HMAC-SHA512 with secret key in java
Yet nothing seems to work. I'm pretty confused about this, and would be glad if anybody could explain to me, what am i missing.
I'm have encrypted a text file on Linux using:
gpg --cipher-algo AES256 -c file.txt
That command asks for a passphrase, let's say we enter "123" here.
This file can be trivially decrypted:
gpg -d file.txt.gpg
Now I like to decrypt this file in Java, but can't quite find out how to do this using the passphrase "123". Specifically, it's not entirely clear what the salt and initial vector is, and what else is needed.
GnuPG implements the OpenPGP protocol, which is not directly support by Java's native classes. OpenPGP has its own file format, but also uses a slightly different variant of the CFB mode.
Instead of implementing all that on your own, better go for the Bouncy Castle library. It also provides an example how to decrypt a symmetrically encrypted message, which boils down to those relevant calls to decrypt an OutputStream out (some more code to determine the used algorithm parameter and compression is also provided in the linked example):
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(algorithm).setSecureRandom(
new SecureRandom()).setProvider("BC"));
encGen.addMethod(
new JcePBEKeyEncryptionMethodGenerator(passPhrase).setProvider("BC"));
OutputStream encOut = encGen.open(out, compressedData.length);
I have an API spec that reads:
Encryption Algorithm
The API utilizes the AES-128 (also known as Rijndael-128) algorithm with a 192-bit key in
CBC mode for encryption and decryption of sensitive pieces of information – the password parameter in the user/signin and user/signup methods, the authentication token, etc. The steps of the algorithm are listed below:
Encryption
Pad the input data so that its size is a multiple of the encryption algorithm block size – 16 bytes. In case the length of input data is a multiple of 16, a block of additional 16 bytes needs to be appended. The value of each pad byte is the number of pad bytes as an 'unsigned char'. That is, the last byte of the padded data should always be between 0x01 and 0x10.
Generate a 16-byte long initialization vector (IV) for the encryption algorithm.
Encrypt the padded data using AES-128 with the EK and the generated IV.
Combine the IV with the encrypted data.
Encode the result with urlsafe Base64. The urlsafe Base46 alphabet uses '–' instead of '+' and '_' instead of '/'.
Decryption
Base64-decode the input data.
Extract the first 16 bytes – these are the IV for the AES algorithm.
Decrypt the data using AES-128 with the EK and IV.
Read the value of the last byte of the decrypted data and remove that many bytes off its tail.
The only example provided by the supplier of this API is in PHP, using mcrypt. I know absolutely nothing about PHP, and am not an encryption expert. I need to be able to represent the above algorithm using ColdFusion 10.
I started by trying to take the example PHP files and find equivalents in either the ColdFusion tag or function library, and then by looking for a Java library with the same interface. I just don't know enough to make this happen.
Is there someone here that can point me in the right direction, or work with me offline to assist?
EDIT:
Here's the example given, for the basic task of doing a "check" on the keys (partner key and encryption key) provided to me for use with the API.
Object Client.php, has this constructor:
public function __construct($hostApiUrl, $partnerKey, $encryptionKey, $token = null)
{
$this->_pk = $partnerKey;
$this->_ek = $encryptionKey;
$this->_crypt = new Crypt($encryptionKey);
$this->_url = rtrim($hostApiUrl, '/') . self::BASE_URL;
if ($token) {
$this->setUserSession($token);
}
}
and this is the function I'm attempting to use:
public function checkKeys()
{
$secret = $this->_encodeParam($this->_ek);
$result = $this->call('partner/checkkeys', array(
'secret' => $secret
));
if (!$result || !$this->_isCodeOk($result->code)) {
return false;
}
return true;
}
So the client object already has the partner key and encryption key when this method is called, obviously.
so the "secret" is created by "encoding" the encryption key provided, using _encodeParam() method. that looks like this:
protected function _encodeParam($secret)
{
$secret = "{$secret}:{$this->_pk}";
return $this->_crypt->encrypt($secret);
}
so the secret is appended with the partner key. and then encrypted using this method in the crypt object (AES_BLOCK_SIZE is set as 16):
public function encrypt($data)
{
$pad = self::AES_BLOCK_SIZE - strlen($data) % self::AES_BLOCK_SIZE;
$data .= str_repeat(chr($pad), $pad);
if (stristr(PHP_OS, 'win') !== false) {
$random_source = MCRYPT_RAND;
} else {
$random_source = MCRYPT_DEV_URANDOM;
}
$iv = mcrypt_create_iv(self::AES_BLOCK_SIZE, $random_source);
mcrypt_generic_init($this->_td, $this->_key, $iv);
$data = $iv . mcrypt_generic($this->_td, $data);
mcrypt_generic_deinit($this->_td);
return self::urlsafe_b64encode($data);
}
this is returned back to the above checkKeys() function which sends the request to the API, which then returns a response. That actual API call is a POST which is easy enough to generate of course, but all those encryption hoops, including the MCRYPT library calls, are where I get stuck trying to determine the equivalent in CF10 or Java.
If I were to get an example thus far, I think I'd stand a chance of replicating the other functions in the crypt object (the ones that are even necessary, which may not be, since some may be built right into the CF encrypt() and decrypt() functions). This seems like a reasonable starting point, however.
Something in the back of my head is telling me I'm missing something obvious here.
I'm integrating an existing java project with a third-party api that uses an md5 hash of an api key for authentication. It's not working for me, and during debugging I realized that the hashes I'm generating don't match the examples that they've supplied. I've found some websites that create MD5 hashes from strings to check their examples, and as far as I can tell I'm wrong and they're right.
for example, according to this website, the string "hello" generates a hash of "5d41402abc4b2a76b9719d911017c592". (FWIW I don't know anything about this website except that it seems to correctly hash the examples that I have). When I run it through my code I get:
XUFAKrxLKna5cZ2REBfFkg==
Here is the simple method I'm using to generate the md5 hash/string.:
private String md5(String md5Me) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
md.reset();
md.update(md5Me.getBytes("UTF-8"));
return Base64.encodeBase64String(md.digest());
}
I used a very similar method to successfully authenticate a different API using the SHA1 algorithm last week. I'm wondering if the problem is related to the org.apache.commons.net.util.Base64.encodeBase64String... Any help is greatly appreciated, if only some tests to see if the byteArray is correct but the converted string is wrong.
for example, according to this website, the string "hello" generates a hash of "5d41402abc4b2a76b9719d911017c592". (FWIW I don't know anything about this website except that it seems to correctly hash the examples that I have). When I run it through my code I get:
XUFAKrxLKna5cZ2REBfFkg==
Both are correct ways of representing the same sixteen-byte hash. 5d41402abc4b2a76b9719d911017c592 represents each byte of the hash as two hexadecimal digits, whereas XUFAKrxLKna5cZ2REBfFkg== uses Base-64 to represent every three bytes of the hash as four characters.
To generate the hexadecimal-version that this third-party API is expecting, you can change this:
Base64.encodeBase64String(md.digest());
to this:
String.format("%032x", new BigInteger(1, md.digest()));
(mostly taken from this StackOverflow answer).
However, you might want to consider using an external library for this. Perception, in a comment above, mentions Apache Commons DigestUtils. If you use that, you'll want the md5hex method.
The md5 Hash algorithm is part of the core java API so there is no need for any external libraries. Here is the method I used to encrypt a password with MD5.
import java.security.MessageDigest;
/**
* Use to encrypt passwords using MD5 algorithm
* #param password should be a plain text password.
* #return a hex String that results from encrypting the given password.
*/
public static String encryptPassword(String password) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(password.getBytes());
byte byteData[] = md.digest();
StringBuffer hexString = new StringBuffer();
for (int i=0;i<byteData.length;i++) {
String hex=Integer.toHexString(0xff & byteData[i]);
if(hex.length()==1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
catch(java.security.NoSuchAlgorithmException missing) {
return "Error.";
}
}
I am trying to implement a PKI verification scheme, where a message string is signed with a private key on server, the signature is stored on the client along with the message string. The client then verifies the signature using a public key.
The restrictions of my environment are, the server is Google App Engine and the client is a Java program. I have played with Java-only and Python-only solutions of PKI verification and got them to work, however when doing one operation in Python and another in Java is posing problem, mainly due to Key file format restrictions and my limited understanding of cryptography terminology.
One of the biggest limitations is crypto support in GAE. The only library supported is PyCrypto and this library can't read public/private keys stored in PEM, DER or X509 formats. As far as I could find, only M2Crypto supports reading from these files, but it can't be used inside GAE because it's a wrapper around openssl, so not a pure python solution. Even if I could find a way to translate the public/private keys from PEM/DER/X509 to the format that PyCrypto understands, that will work for me. But I couldn't find any way to do it. Any ideas there?
I found one possible solution in the form of tlslite. tlslite could read a private key from PEM file and create a signature. Here is the code.
from tlslite.utils.cryptomath import bytesToBase64
from tlslite.utils.keyfactory import parsePEMKey
s = open('private.pem').read()
key = parsePEMKey(s)
doc = 'Sample text'
bytes = array('B')
bytes.fromstring(doc)
print bytesToBase64(key.sign(bytes))
The corresponding Java code I used to verify the signature is.
String signAlgo = "SHA1WithRSAEncryption";
// read public key from public.der
byte[] encodedKey = new byte[294]; // shortcut hardcoding
getAssets().open("public.der").read(encodedKey);
// create public key object
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pk = kf.generatePublic(publicKeySpec);
// read signature (created by python code above)
byte[] encodedSig = new byte[345];
getAssets().open("signature.txt").read(encodedSig);
byte[] decodedSig = Base64.decodeBase64(encodedSig);
// Do verification
Signature verifyalg = Signature.getInstance(signAlgo);
verifyalg.initVerify(pk);
verifyalg.update(message.getBytes());
Log.d(TAG, "Verif : "+verifyalg.verify(decodedSig));
The verification fails.
I suspected if the tlslite is using different algorithm for signature creation than what the java code expects.
So I tried to find that out.
On python side
print key.getSigningAlgorithm()
gave me
pkcs1-sha1
on Java side, I tried to find all supported algorithms with this code:
Set<String> algos = java.security.Security.getAlgorithms("Signature");
for(String algo : algos) {
Log.d(TAG, algo);
}
That gave me
MD4WithRSAEncryption
RSASSA-PSS
SHA1withDSA
SHA1withRSA/ISO9796-2
1.2.840.113549.1.1.10
SHA512withRSA/PSS
MD5withRSA/ISO9796-2
DSA
SHA512WithRSAEncryption
SHA224withRSA/PSS
NONEWITHDSA
SHA256withRSA/PSS
SHA224WithRSAEncryption
SHA256WithRSAEncryption
SHA1withRSA/PSS
SHA1WithRSAEncryption
SHA384withRSA/PSS
SHA384WithRSAEncryption
MD5WithRSAEncryption
I tried all the SHA1 values on the Java side. But none helped to verify the signature generated by tlslite with pkcs1-sha1 algo. Any idea about this mapping?
These are different operations. In Python, you need to use hashAndSign. The default happens to be SHA1 hash.
Keyczar should work fine on App Engine, and is available in both Java and Python flavours.