How should I convert this java DES program to PHP? - java

I have a DES Algorithm use java ,now I need convert this java program for php, I don't know java cipher.init method's third parameters SecureRandom ,So I use my php Des program to encrypt a string ,but I got a different result with java Des.
Here is my Java DES:
public static String encode(String srcStr) {
if (srcStr == null)
return null;
String dst = null;
byte[] result = encrypt2(srcStr.getBytes(), "h43au76U");
if (result == null)
return null;
System.out.println(result);
dst = byte2HexStr(result, result.length);
return dst;
}
private static final char[] mChars = "0123456789ABCDEF".toCharArray();
public static String byte2HexStr(byte[] b, int iLen) {
if (b == null)
return null;
StringBuilder sb = new StringBuilder();
for (int n = 0; n < iLen; n++) {
sb.append(mChars[(b[n] & 0xff) >> 4]);
sb.append(mChars[b[n] & 0xf]);
}
return sb.toString().trim().toUpperCase(Locale.US);
}
private static byte[] encrypt2(byte[] datasource, String password) {
byte[] is;
try {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(password.getBytes("UTF-8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
javax.crypto.SecretKey securekey
= keyFactory.generateSecret(desKey);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(1, securekey, random);
is = cipher.doFinal(datasource);
} catch (Throwable e) {
e.printStackTrace();
return null;
}
return is;
}
And this is my php des:
function encrypt($input,$key,$iv=0){
$size = mcrypt_get_block_size(MCRYPT_DES,MCRYPT_MODE_CBC); //3DES加密将MCRYPT_DES改为MCRYPT_3DES
$input =pkcs5_pad($input, $size); //如果采用PaddingPKCS7,请更换成PaddingPKCS7方法。
$td = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_CBC, '');
#mcrypt_generic_init($td, $key,$iv);
$data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
// return $data;
return strtoupper(bin2hex($data));
}
I got a different result, why? And I don't know if SecureRandom is a iv ?

Always use a fully qualified Cipher string. Cipher.getInstance("DES"); may result in different ciphers depending on the default security provider. It most likely results in "DES/ECB/PKCS5Padding", but it doesn't have to be. If it changes, you'll lose compatibility between different JVMs.
What you need to do in PHP to achieve compatibility with Java is to use ECB mode instead of CBC mode and apply PKCS#5 padding (same as PKCS#7 padding). This answer shows an implementation of that padding. You just have to use the correct block size which is 8 for DES.
Never use ECB mode. It's deterministic and therefore not semantically secure. You should at the very least use a randomized mode like CBC or CTR. It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme.
The IV must be unpredictable (read: random). Don't use a static IV, because that makes the cipher deterministic and therefore not semantically secure. An attacker who observes ciphertexts can determine when the same message prefix was sent before. The IV is not secret, so you can send it along with the ciphertext. Usually, it is simply prepended to the ciphertext and sliced off before decryption.

public static function encryptDes($data, $key)
{
$paddedData = static::pad($data);
$opts = OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA;
return strtoupper(bin2hex(openssl_encrypt($paddedData, 'DES-ECB', $key, $opts)));
}
public static function decryptDes($data, $key)
{
$data = hex2bin($data);
$opts = OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA;
return static::unpad(openssl_decrypt($data, 'DES-ECB', $key, $opts));
}
private static function pad($text)
{
$blockSize = 8;
$length = strlen($text);
$pad = $blockSize - ($length % $blockSize);
return str_pad($text, $length + $pad, chr($pad));
}
private static function unpad($text)
{
$length = ord($text[strlen($text) - 1]);
return substr($text, 0, -$length);
}

Related

Encrypting Java then Decrypting C# AES256 Encryption with HMACSHA256, Padding is invalid

I'm currently running into an issue where our decryption portion of our C# site is having trouble with the padding with the encrypted string from java. The .Net code throws this error "Padding is invalid and cannot be removed". The _signKey and _encKey are both 64 bytes.
public String encryptString(String plainText) {
byte[] ciphertext;
byte[] iv = new byte[16];
byte[] plainBytes = plainText.getBytes(StandardCharsets.UTF_8);
String _signKey = "****************************************************************";
String _encKey = "****************************************************************";
try {
Mac sha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec shaKS = new SecretKeySpec(_signKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256.init(shaKS);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
byte[] sessionKey = sha256.doFinal((_encKey + iv).getBytes(StandardCharsets.UTF_8));
// Perform Encryption
SecretKeySpec eks = new SecretKeySpec(sessionKey, "AES");
cipher.init(Cipher.ENCRYPT_MODE, eks, ivParams);
ciphertext = cipher.doFinal(plainBytes);
System.out.println("ciphertext= " + new String(ciphertext));
// Perform HMAC using SHA-256 on ciphertext
SecretKeySpec hks = new SecretKeySpec(_signKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(hks);
ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream();
outputStream2.write(iv);
outputStream2.write(ciphertext);
outputStream2.flush();
outputStream2.write(mac.doFinal(outputStream2.toByteArray()));
return Base64.encodeBase64String(outputStream2.toByteArray());
} catch (Exception e) {
e.printStackTrace();
}
return plainText;
}
Does does encrypt the string properly as far as I can tell. We cannot change any code on the .Net side to decrypt this because this is being used today.
public static string DecryptString(string ciphertext)
{
using (HMACSHA256 sha256 = new HMACSHA256(Encoding.UTF8.GetBytes(_signKey)))
{
// Convert message to bytes
byte[] encBytes = Convert.FromBase64String(ciphertext);
// Get arrays for comparing HMAC tags
byte[] sentTag = new byte[sha256.HashSize / 8];
byte[] calcTag = sha256.ComputeHash(encBytes, 0, (encBytes.Length - sentTag.Length));
// If message length is too small return null
if (encBytes.Length < sentTag.Length + _ivLength) { return null; }
// Copy tag from end of encrypted message
Array.Copy(encBytes, (encBytes.Length - sentTag.Length), sentTag, 0, sentTag.Length);
// Compare tags with constant time comparison, return null if no match
int compare = 0;
for (int i = 0; i < sentTag.Length; i++) { compare |= sentTag[i] ^ calcTag[i]; }
if (compare != 0) { return null; }
using (AesCryptoServiceProvider csp = new AesCryptoServiceProvider())
{
// Set parameters
csp.BlockSize = _blockBits;
csp.KeySize = _keyBits;
csp.Mode = CipherMode.CBC;
csp.Padding = PaddingMode.PKCS7;
// Copy init vector from message
var iv = new byte[_ivLength];
Array.Copy(encBytes, 0, iv, 0, iv.Length);
// Derive session key
byte[] sessionKey = sha256.ComputeHash(Encoding.UTF8.GetBytes(_encKey + iv));
// Decrypt message
using (ICryptoTransform decrypt = csp.CreateDecryptor(sessionKey, iv))
{
return Encoding.UTF8.GetString(decrypt.TransformFinalBlock(encBytes, iv.Length, encBytes.Length - iv.Length - sentTag.Length));
}
}
}
}
If there is anything that sticks out it would be appreciated for the reply.
I didn't read all your code, but this line in Java:
byte[] sessionKey = sha256.doFinal((_encKey + iv).getBytes(StandardCharsets.UTF_8));
does nothing useful or sensible. The "+" operator does string concatenation, but iv is a byte[], not a String. So java uses iv.toString(), which simply returns a String containing something like [B#1188e820 which is meaningless in this context.
Refer four java code and DotNet code:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //Java
csp.Padding = PaddingMode.PKCS7; //.Net
You are essentially using different padding, that is the probable source of error; however, there is an alternate view, Refer this great post and this for general fundamentals on padding
The cipher suites supported by deafult Oracle JVM implementation are here
If you notice it does not have 'AES/CBC/PKCS7Padding', a PKCS#7 padding implementation is available in sun.security package, refer this, otherwise you could use Bouncy Castle packages. It would be recommendable to use Bouncy Castle as com.sun package are generally considered unsupported.

javax.crypto.Cipher equivalent code in Nodejs Crypto Javascript

I'm trying to convert below java code into nodejs.
public static String encrypt(String accessToken) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
String merchantKey = "11111111111111111111";
String st = StringUtils.substring(merchantKey, 0, 16);
System.out.println(st);
Key secretKey = new SecretKeySpec(st.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedByte = cipher.doFinal(accessToken.getBytes());
// convert the byte to hex format
StringBuffer sb = new StringBuffer();
for (int i = 0; i < encryptedByte.length; i++) {
sb.append(Integer.toString((encryptedByte[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
Here is what I was able to figure out-
function freeChargeEncryptAES(token){
var fcKey = "11111111111111111111".substring(0, 16);
var cipher = crypto.createCipher('aes-128-ecb', fcKey, "");
var encrypted = cipher.update(token,'ascii','hex');
encrypted += cipher.final('hex');
return encrypted;
}
I'm not able to get same output. For example if
token = "abcdefgh"
Java Code output - bc02de7c1270a352a98faa686f155df3
Nodejs Code output - eae7ec6943953aca94594641523c3c6d
I've read from this answer that by default encryption algorithm is aes-ecb which does not need IV. As the key length is 16, I'm assuming aes-128-ecb (16*8 = 128) is the algorithm that I should use.
Can someone help me figure out the problem ??
Just need to change -
crypto.createCipher('aes-128-ecb', fcKey, "");
to
crypto.createCipheriv('aes-128-ecb', fcKey, "");
Reason is simple - createCipher method treats second parameter as Encryption Password while it is an Encryption Key.
My bad, even after reading this answer, I've used wrong method (crypto.createCipher instead of crypto.createCipheriv). Below is proper working code in nodejs. That was all needed.
function freeChargeEncryptAES(token){
var fcKey = "11111111111111111111".substring(0, 16);
var cipher = crypto.createCipheriv('aes-128-ecb', fcKey, "");
var encrypted = cipher.update(token,'ascii','hex');
encrypted += cipher.final('hex');
return encrypted;
}

Blowfish example where automatically pad and unpad the key to size

Blowfish is capable of strong encryption and can use key sizes up to 56 bytes (a 448 bit key).
The key must be a multiple of 8 bytes (up to a maximum of 56).
I want to write example will automatically pad and unpad the key to size. Because Blowfish creates blocks of 8 byte encrypted output, the output is also padded and unpadded to multiples of 8 bytes.
actually want to write java code to simulate-
http://webnet77.com/cgi-bin/helpers/blowfish.pl
I am using info for tool-
ALGORITM = "Blowfish";
HEX KEY = "92514c2df6e22f079acabedce08f8ac3";
PLAIN_TEXT = "sangasong#song.com"
Tool returns-
CD3A08381467823D4013960E75E465F0B00C5E3BAEFBECBB
Please suggest.
Tried the java code:
public class TestBlowfish
{
final String KEY = "92514c2df6e22f079acabedce08f8ac3";
final String PLAIN_TEXT = "sangasong#song.com";
byte[] keyBytes = DatatypeConverter.parseHexBinary(KEY);
}
public static void main(String[] args) throws Exception
{
try
{
byte[] encrypted = encrypt(keyBytes, PLAIN_TEXT);
System.out.println( "Encrypted hex: " + Hex.encodeHexString(encrypted));
}catch (GeneralSecurityException e)
{
e.printStackTrace();
}
}
private static byte[] encrypt(byte[] key, String plainText) throws GeneralSecurityException
{
SecretKey secret_key = new SecretKeySpec(key, "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, secret_key);
return cipher.doFinal(plainText.getBytes());
}
Result -
Encrypted hex: 525bd4bd786a545fe7786b0076b3bbc2127425f0ea58c29d
So the script uses an incorrect version of PKCS#7 padding that does not pad when the size of the input is already dividable by the block size - both for the key and the plaintext. Furthermore it uses ECB mode encryption. Neither of which should be used in real life scenarios.
The following code requires the Bouncy Castle provider to be added to the JCE (Service.addProvider(new BouncyCastleProvider())) and that the Hex class of Bouncy Castle libraries is in the class path.
Warning: only tested with limited input, does not cut the key size if the size of the key is larger than the maximum.
WARNING: THE FOLLOWING CODE IS NOT CRYPTOGRAPHICALLY SOUND
import org.bouncycastle.util.encoders.Hex;
public class BadBlowfish {
private static SecretKey createKey(String theKey) {
final byte[] keyData = theKey.getBytes(StandardCharsets.US_ASCII);
final byte[] paddedKeyData = halfPadPKCS7(keyData, 8);
SecretKey secret = new SecretKeySpec(paddedKeyData, "Blowfish");
return secret;
}
private static byte[] halfUnpadPKCS7(final byte[] paddedPlaintext, int blocksize) {
int b = paddedPlaintext[paddedPlaintext.length - 1] & 0xFF;
if (b > 0x07) {
return paddedPlaintext.clone();
}
return Arrays.copyOf(paddedPlaintext, paddedPlaintext.length - b);
}
private static byte[] halfPadPKCS7(final byte[] plaintext, int blocksize) {
if (plaintext.length % blocksize == 0) {
return plaintext.clone();
}
int newLength = (plaintext.length / blocksize + 1) * blocksize;
int paddingLength = newLength - plaintext.length;
final byte[] paddedPlaintext = Arrays.copyOf(plaintext, newLength);
for (int offset = plaintext.length; offset < newLength; offset++) {
paddedPlaintext[offset] = (byte) paddingLength;
}
return paddedPlaintext;
}
public static void main(String[] args) throws Exception {
Cipher cipher = Cipher.getInstance("Blowfish/ECB/NoPadding");
SecretKey key = createKey("123456781234567");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plaintextData = cipher.doFinal(Hex.decode("085585C60B3D23257763E6D8BB0A0891"));
byte[] unpaddedPlaintextData = halfUnpadPKCS7(plaintextData, cipher.getBlockSize());
String plaintextHex = Hex.toHexString(unpaddedPlaintextData);
System.out.println(plaintextHex);
String plaintext = new String(unpaddedPlaintextData, StandardCharsets.UTF_8);
System.out.println(plaintext);
}
}
I am not sure about the relevance of this question: IMHO there is no point of getting the same output as this script: you have no guaranty about how secure/efficient it is...
What raises my eyebrow is the part about the padding: there are several solution to pad a block, some of then are simple but very unsecured, and maybe this script is using one of these "bad" solution.
Did you check that your program is able to retrieve the correct plain text ? (you will need to code the matching decrypt function).
If so, it means that it works correctly and it can be used for whatever your original purpose was, regardless what the ouput of this script is...

PHP Java AES CBC Encryption Different Results

PHP Function:
$privateKey = "1234567812345678";
$iv = "1234567812345678";
$data = "Test string";
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $privateKey, $data, MCRYPT_MODE_CBC, $iv);
echo(base64_encode($encrypted));
Result: iz1qFlQJfs6Ycp+gcc2z4w==
Java Function
public static String encrypt() throws Exception{
try{
String data = "Test string";
String key = "1234567812345678";
String iv = "1234567812345678";
javax.crypto.spec.SecretKeySpec keyspec = new javax.crypto.spec.SecretKeySpec(key.getBytes(), "AES");
javax.crypto.spec.IvParameterSpec ivspec = new javax.crypto.spec.IvParameterSpec(iv.getBytes());
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(data.getBytes());
return new sun.misc.BASE64Encoder().encode(encrypted);
}catch(Exception e){
return null;
}
}
returns null.
Please note that we are not allowed to change the PHP code. Could somebody please help us get the same results in Java? Many thanks.
You'd have had a better idea of what was going on if you didn't simply swallow up possible Exceptions inside your encrypt() routine. If your function is returning null then clearly an exception happened and you need to know what it was.
In fact, the exception is:
javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:854)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:828)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
at Encryption.encrypt(Encryption.java:20)
at Encryption.main(Encryption.java:6)
And sure enough, your plaintext is only 11 Java characters long which, in your default encoding, will be 11 bytes.
You need to check what the PHP mcrypt_encrypt function actually does. Since it works, it is clearly using some padding scheme. You need to find out which one it is and use it in your Java code.
Ok -- I looked up the man page for mcrypt_encrypt. It says:
The data that will be encrypted with the given cipher and mode. If the size of the data is not n * blocksize, the data will be padded with \0.
So you need to replicate that in Java. Here's one way:
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Encryption
{
public static void main(String args[]) throws Exception {
System.out.println(encrypt());
}
public static String encrypt() throws Exception {
try {
String data = "Test string";
String key = "1234567812345678";
String iv = "1234567812345678";
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
// We need to pad with zeros to a multiple of the cipher block size,
// so first figure out what the size of the plaintext needs to be.
byte[] dataBytes = data.getBytes();
int plaintextLength = dataBytes.length;
int remainder = plaintextLength % blockSize;
if (remainder != 0) {
plaintextLength += (blockSize - remainder);
}
// In java, primitive arrays of integer types have all elements
// initialized to zero, so no need to explicitly zero any part of
// the array.
byte[] plaintext = new byte[plaintextLength];
// Copy our actual data into the beginning of the array. The
// rest of the array is implicitly zero-filled, as desired.
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(plaintext);
return new sun.misc.BASE64Encoder().encode(encrypted);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
And when I run that I get:
iz1qFlQJfs6Ycp+gcc2z4w==
which is what your PHP program got.
Update (12 June 2016):
As of Java 8, JavaSE finally ships with a documented base64 codec. So instead of
return new sun.misc.BASE64Encoder().encode(encrypted);
you should do something like
return Base64.Encoder.encodeToString(encrypted);
Alternatively, use a 3rd-party library (such as commons-codec) for base64 encoding/decoding rather than using an undocumented internal method.

PHP Equivalent for Java Triple DES encryption/decryption

Am trying to decrypt a key encrypted by Java Triple DES function using PHP mcrypt function but with no luck. Find below the java code
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Encrypt3DES {
private byte[] key;
private byte[] initializationVector;
public Encrypt3DES(){
}
public String encryptText(String plainText, String key) throws Exception{
//---- Use specified 3DES key and IV from other source --------------
byte[] plaintext = plainText.getBytes();
byte[] myIV = key.getBytes();
byte[] tdesKeyData = {(byte)0xA2, (byte)0x15, (byte)0x37, (byte)0x08, (byte)0xCA, (byte)0x62,
(byte)0xC1, (byte)0xD2, (byte)0xF7, (byte)0xF1, (byte)0x93, (byte)0xDF,
(byte)0xD2, (byte)0x15, (byte)0x4F, (byte)0x79, (byte)0x06, (byte)0x67,
(byte)0x7A, (byte)0x82, (byte)0x94, (byte)0x16, (byte)0x32, (byte)0x95};
Cipher c3des = Cipher.getInstance("DESede/CBC/PKCS5Padding");
SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
IvParameterSpec ivspec = new IvParameterSpec(myIV);
c3des.init(Cipher.ENCRYPT_MODE, myKey, ivspec);
byte[] cipherText = c3des.doFinal(plaintext);
sun.misc.BASE64Encoder obj64=new sun.misc.BASE64Encoder();
return obj64.encode(cipherText);
}
public String decryptText(String encryptText, String key) throws Exception{
byte[] initializationVector = key.getBytes();
byte[] tdesKeyData = {(byte)0xA2, (byte)0x15, (byte)0x37, (byte)0x08, (byte)0xCA, (byte)0x62,
(byte)0xC1, (byte)0xD2, (byte)0xF7, (byte)0xF1, (byte)0x93, (byte)0xDF,
(byte)0xD2, (byte)0x15, (byte)0x4F, (byte)0x79, (byte)0x06, (byte)0x67,
(byte)0x7A, (byte)0x82, (byte)0x94, (byte)0x16, (byte)0x32, (byte)0x95};
byte[] encData = new sun.misc.BASE64Decoder().decodeBuffer(encryptText);
Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
IvParameterSpec ivspec = new IvParameterSpec(initializationVector);
decipher.init(Cipher.DECRYPT_MODE, myKey, ivspec);
byte[] plainText = decipher.doFinal(encData);
return new String(plainText);
}
}
I want to write a PHP function equivalent to the decryptText Java function above. am finding difficulty in generating the exact IV value generated by the Java code for encryption, which is required for the decryption.
This is the PHP equivalent of your Java code (I have copied the PKCS#5-padding from the comment 20-Sep-2006 07:56 of The mcrypt reference)
function encryptText($plainText, $key) {
$keyData = "\xA2\x15\x37\x08\xCA\x62\xC1\xD2"
. "\xF7\xF1\x93\xDF\xD2\x15\x4F\x79\x06"
. "\x67\x7A\x82\x94\x16\x32\x95";
$padded = pkcs5_pad($plainText,
mcrypt_get_block_size("tripledes", "cbc"));
$encText = mcrypt_encrypt("tripledes", $keyData, $padded, "cbc", $key);
return base64_encode($encText);
}
function decryptText($encryptText, $key) {
$keyData = "\xA2\x15\x37\x08\xCA\x62\xC1\xD2"
. "\xF7\xF1\x93\xDF\xD2\x15\x4F\x79\x06"
. "\x67\x7A\x82\x94\x16\x32\x95";
$cipherText = base64_decode($encryptText);
$res = mcrypt_decrypt("tripledes", $keyData, $cipherText, "cbc", $key);
$resUnpadded = pkcs5_unpad($res);
return $resUnpadded;
}
function pkcs5_pad ($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
function pkcs5_unpad($text)
{
$pad = ord($text{strlen($text)-1});
if ($pad > strlen($text)) return false;
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false;
return substr($text, 0, -1 * $pad);
}
But there are some problems you should be aware of:
In your Java code you call String.getBytes() without indicating an encoding. This makes your code non portable if your clear text contains non ASCII-characters such as umlauts, because Java uses the system-default character set. If you can change that I certainly would do so. I recommend you to use utf-8 on both sides (Java and PHP).
You have hard coded the cipher-key and use the IV as "key". I'm by no means a crypto-expert but to me it just feels wrong and may open a huge security leak.
Create a random IV and just concatenate it at the start or at the end of your message. Since the size of the IV is AFAIK equal to the block-size of your cipher you just remove that much bytes from the start or end and have easily separated the IV from the message.
As for the key, it's best to use some kind of key derivation method to generate a key with the right size from a "human generated" password.
Of course, if you have to fulfil some given requirements you can't change your method.
The answer is almost good! Just reverse $keyData and $key in
$encText = mcrypt_encrypt("tripledes", $keyData, $padded, "cbc", $key);
and
$res = mcrypt_decrypt("tripledes", $keyData, $cipherText, "cbc", $key);
otherwise you will always use the same 3DES key. And it's better to rename $keyData to $iv.
Anyway, thanks a lot for the Java sample and the Php-Java translation.

Categories