I am trying to find implementing this Java encryption algorithm in PHP, but I do not have any experience in PHP.
I have this DESede/ECB/PKCS5Padding encryption utils code in Java.
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
public class DESUtil {
private static final String KEY_ALGORITHM = "DESede";
private static final String DEFAULT_CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";
public static String encrypt(String content, final String key) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
byte[] byteContent = content.getBytes(StandardCharsets.UTF_8.name());
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));
byte[] result = cipher.doFinal(byteContent);
return Base64.encodeBase64String(result);
} catch (Exception ex) {
System.out.println("error:" + ex.getMessage());
}
return null;
}
public static String decrypt(String content, final String key) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));
byte[] result = cipher.doFinal(Base64.decodeBase64(content));
return new String(result, StandardCharsets.UTF_8.name());
} catch (Exception ex) {
System.out.println("error:" + ex.getMessage());
}
return null;
}
public static SecretKeySpec getSecretKey(final String key) {
KeyGenerator kg = null;
try {
byte[] bytes = key.getBytes(StandardCharsets.UTF_8.name());
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(bytes);
kg.init(secureRandom);
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
} catch (Exception ex) {
System.out.println("error:" + ex.getMessage());
}
return null;
}
}
Run test, I got this
System.out.println("Result:" + DESUtil.encrypt("abc", "123456"));
// Result:9huQhFxzOmA=
But I use openssl, the result is different
<?php
$key = "123456";
$data = "abc";
$out = openssl_encrypt($data, 'DES-EDE3', $key, OPENSSL_RAW_DATA);
echo base64_encode($out);
// VxvdZgL08kU=
2021-03-29 15:00 update.
How to implementing DESede + SHA1PRNG in php,I try this(Java Aes class convert to php) post's answer(AES + SHA1PRNG),but result is different
<?php
$key = "123456";
$data = "abc";
$key = substr(openssl_digest(openssl_digest($password, 'sha1', true), 'sha1', true), 0, 16);
$out = openssl_encrypt($data, 'DES-EDE3', $key, OPENSSL_RAW_DATA);
echo base64_encode($out);
// rsXHh1tIzSs=
2021-03-29 18:25 update. try again.
<?php
// this key is 123456, generate by java kg.generateKey to base64 encode.
$key = "a7WDf7ZDKRBe5VeM2nzHf9PLKtkfZC9G";
$data = "abc";
$key = base64_decode($key);
$out = openssl_encrypt($data, 'DES-EDE3', $key, OPENSSL_RAW_DATA);
echo base64_encode($out);
// 9huQhFxzOmA=
// this result is correct, but how to implementing DESede + SHA1PRNG in php?
What is the right algorithm? How to implement this?
Related
I am unable to decrypt data on iOS(Swift) which I am getting from the Java server. But if I encrypt a data on iOS and then decrypt, it works well. There might be some variance on both side's AES code which I am not able to identify. Please help me.
Similar question asked here: https://github.com/krzyzanowskim/CryptoSwift/issues/458
iOS Decryptor
let password = "SOME_ENCRYPTION_KEY"
let iv = AES256Crypter.randomIv()
let key = try AES256Crypter.createKey(password: password.data(using: .utf8)!, salt: salt)
let aes = try AES256Crypter(key: key, iv: iv)
let encryptedData = "encrypted_data".data(using: .utf8)
let decryptedData = try aes.decrypt(encryptedData!)
let decryptedString = String(decoding: decryptedData, as: UTF8.self)
print("Decrypted string: \(decryptedString)")
Java Encryptor
SecretKeySpec secretKey;
try {
byte[] key = ENCRYPTION_KEY.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
secretKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
} catch (Exception e) {
System.out.println("\nException while encrypting " + strToEncrypt + " \nerror: " + e.getMessage());
}
Below is the code for Encryption in Java
and Decryption for iOS(Swift and Android(Kotlin). This works well but I am still open for a better solution.
Java Code
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class EncryptionUtils {
private static String ENCRYPTION_KEY = "1234512345123456";
public static void main(String[] args) {
String encyString = new EncryptionUtils().encrypted("HJUSER153");
System.out.println("Encrypted String:" + encyString);
}
public String encrypted(String strToEncrypt) {
try {
IvParameterSpec ivspec = new IvParameterSpec(ENCRYPTION_KEY.getBytes());
SecretKeySpec keyspec = new SecretKeySpec(ENCRYPTION_KEY.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
//encrypted = cipher.doFinal(text.getBytes());
} catch (Exception e) {
System.out.println("\nException while encrypting " + strToEncrypt + " \nerror: " + e.getMessage());
}
return null;
}
}
iOS Swift Code
Add this in pod file -
pod 'CryptoSwift'
import CryptoSwift
func decrypt(input:String)->String?{
let key = "1234512345123456"
do{
let d=Data(base64Encoded: input)
let decrypted = try AES(key: key, iv: key, padding: .pkcs5).decrypt(
d!.bytes)
return String(data: Data(decrypted), encoding: .utf8)
}catch{
}
return nil
}
Android
import android.util.Base64
import java.security.NoSuchAlgorithmException
import javax.crypto.Cipher
import javax.crypto.NoSuchPaddingException
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
class CypherHelper {
private var ivspec: IvParameterSpec? = null
private var keyspec: SecretKeySpec? = null
private var cipher: Cipher? = null
private val ENCRYPTION_KEY: String = "1234567890123456"
init {
ivspec = IvParameterSpec(ENCRYPTION_KEY.toByteArray(Charsets.UTF_8))
keyspec = SecretKeySpec(ENCRYPTION_KEY.toByteArray(), "AES")
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
} catch (e: NoSuchPaddingException) {
e.printStackTrace()
}
}
fun decrypt(valueToDecrypt: String): String {
var decryptValue: String = ""
val enc = CypherHelper()
if (valueToDecrypt.isEmpty())
decryptValue = String(enc.decryptInternal(valueToDecrypt)!!)
return decryptValue
}
private fun decryptInternal(code: String?): ByteArray? {
if (code == null || code.isEmpty()) {
throw Exception("Empty string")
}
var decrypted: ByteArray? = null
try {
cipher?.init(Cipher.DECRYPT_MODE, keyspec, ivspec)
decrypted = cipher?.doFinal(Base64.decode(code, Base64.DEFAULT))
} catch (e: Exception) {
throw Exception("[decrypt] " + e.message)
}
return decrypted
}
}
My problem is with symmetric decryption. Not asymmetric decryption. So the correct answer is here Decrypt PGP encrypted file with passphrase only in Java
I use gpg to encrypt "hello":
[root#shc-sma-cd13 opt]# echo "hello" | gpg --symmetric --armor --cipher-algo AES256 --passphrase "2R79P7z5f8350VEp" --batch
-----BEGIN PGP MESSAGE-----
Version: GnuPG v2.0.22 (GNU/Linux)
jA0ECQMC1XpaSrXhBAfU0jsBXw817k4k4iT++AGV8MUev4/gKkuIwAW2VaJsEANa
+0ZuqZgFp/8N7AndRhyNj5WGcloQQkLkwvIV3Q==
=GwQi
-----END PGP MESSAGE-----
I use Java to decrypt the string:
public class AESUtils1 {
private static final String KEY_VAL = "2R79P7z5f8350VEp";
public static String AESDecode(String content) {
try {
SecretKey key = new SecretKeySpec(KEY_VAL.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] byte_content = new BASE64Decoder().decodeBuffer(content);
byte[] byte_decode = cipher.doFinal(byte_content);
String AES_decode = new String(byte_decode, "utf-8");
return AES_decode;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
//如果有错就返加nulll
return null;
}
public static void main(String[] args) {
String encryptString = "jA0ECQMC1XpaSrXhBAfU0jsBXw817k4k4iT++AGV8MUev4/gKkuIwAW2VaJsEANa\n" +
" +0ZuqZgFp/8N7AndRhyNj5WGcloQQkLkwvIV3Q==\n" +
" =GwQi";
String decryptString = AESDecode(encryptString);
System.out.println("decryptString: " + decryptString);
}
}
But it fails with error message:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:936)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2164)
at com.hpe.itsma.itsmaInstaller.AESUtils1.AESDecode(AESUtils1.java:33)
at com.hpe.itsma.itsmaInstaller.AESUtils1.main(AESUtils1.java:57)
decryptString: null
I am curious that what is the real encrypted string from gpg that I can put it into Java. The output of gpg is different from using Java to encrypt "hello".
And another interesting thing is that every time I run command echo "hello" | gpg --symmetric --armor --cipher-algo AES256 --passphrase "2R79P7z5f8350VEp" --batch, the result is always different. Is that possible to decrypt the string which is encrypted by gpg. Or the wrong way I used of gpg?
Thanks all. Finally, I figure out the solution. Cause my data was symmetric encrypted. The decryption will be different from the asymmetric decryption. I put my code below, also you can find the same answer here Decrypt PGP encrypted file with passphrase only in Java
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
import org.bouncycastle.util.io.Streams;
import java.io.*;
import java.security.NoSuchProviderException;
import java.security.Security;
public class SymmetricDecyption {
public static byte[] decrypt(byte[] var0, char[] var1) throws IOException, PGPException, NoSuchProviderException {
ByteArrayInputStream var2 = new ByteArrayInputStream(var0);
InputStream var11 = PGPUtil.getDecoderStream(var2);
PGPObjectFactory var3 = new PGPObjectFactory(var11);
Object var5 = var3.nextObject();
PGPEncryptedDataList var4;
if (var5 instanceof PGPEncryptedDataList) {
var4 = (PGPEncryptedDataList) var5;
} else {
var4 = (PGPEncryptedDataList) var3.nextObject();
}
PGPPBEEncryptedData var6 = (PGPPBEEncryptedData) var4.get(0);
InputStream var7 = var6.getDataStream((new JcePBEDataDecryptorFactoryBuilder((new JcaPGPDigestCalculatorProviderBuilder()).setProvider("BC").build())).setProvider("BC").build(var1));
PGPObjectFactory var8 = new PGPObjectFactory(var7);
PGPCompressedData var9 = (PGPCompressedData) var8.nextObject();
var8 = new PGPObjectFactory(var9.getDataStream());
PGPLiteralData var10 = (PGPLiteralData) var8.nextObject();
return Streams.readAll(var10.getInputStream());
}
public static void main(String[] var0) throws Exception {
String password = "2R79P7z5f8350VEp";
File file = new File("C:\\Users\\zhongtao.CORPDOM\\Desktop\\file.txt.asc");
InputStream input = new FileInputStream(file);
byte[] byt = new byte[input.available()];
input.read(byt);
Security.addProvider(new BouncyCastleProvider());
byte[] var5 = decrypt(byt, password.toCharArray());
System.out.println("Decrypted data is: " + new String(var5));
}
}
I saw some same questions in stack-overflow but it doesn't help me.
I have this php code
$signature=base64_encode(hash_hmac("sha256", trim($xmlReq), $signature_key, True));
I want to write java equivalent to that and this is my java code.
public static String encodeXML(String key, String data) {
String result = "";
try {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
mac.init(secretKeySpec);
result = Base64.encodeBase64String(mac.doFinal(data.getBytes("UTF-8")));
} catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
log.error("exception occured when encording HmacSHA256 hash");
}
return result;
}
but they give different results.
someone help.
Apache Commons Codec
import org.apache.commons.codec.binary.Base64;
....
Base64.encodeBase64String(.....);
PHP Test Code:
$signature=base64_encode(hash_hmac("sha256", 'Message', 'secret', true));
echo $signature;
Java Test Code:
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class TestJava {
public static void main(String[] args) {
try {
String secret = "secret";
String message = "Message";
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
Base64.Encoder encoder = Base64.getEncoder();
String hash = encoder.encodeToString(sha256_HMAC.doFinal(message.getBytes()));
System.out.println(hash);
} catch (Exception e){
System.out.println("Error");
}
}
}
Output for both should be:
qnR8UCqJggD55PohusaBNviGoOJ67HC6Btry4qXLVZc=
Aloha! I'm wondering if there's any decent way to do a good form of encryption on Android without writing my own function to do one.
Are there any libraries I should be using?
You can use AES, DES and 3DES, they all are included in java. I have posted a easy program from here http://sanjaal.com/java/186/java-encryption/tutorial-java-des-encryption-and-decryption/ which is using DES to encrypt/Decrypt
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
class DESEncryption {
private static final String UNICODE_FORMAT = "UTF8";
public static final String DES_ENCRYPTION_SCHEME = "DES";
private KeySpec myKeySpec;
private SecretKeyFactory mySecretKeyFactory;
private Cipher cipher;
byte[] keyAsBytes;
private String myEncryptionKey;
private String myEncryptionScheme;
SecretKey key;
public DESEncryption() throws Exception
{
myEncryptionKey = "ThisIsSecretEncryptionKey";
myEncryptionScheme = DES_ENCRYPTION_SCHEME;
keyAsBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
myKeySpec = new DESKeySpec(keyAsBytes);
mySecretKeyFactory = SecretKeyFactory.getInstance(myEncryptionScheme);
cipher = Cipher.getInstance(myEncryptionScheme);
key = mySecretKeyFactory.generateSecret(myKeySpec);
}
/**
* Method To Encrypt The String
*/
public String encrypt(String unencryptedString) {
String encryptedString = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainText = unencryptedString.getBytes(UNICODE_FORMAT);
byte[] encryptedText = cipher.doFinal(plainText);
BASE64Encoder base64encoder = new BASE64Encoder();
encryptedString = base64encoder.encode(encryptedText);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Method To Decrypt An Ecrypted String
*/
public String decrypt(String encryptedString) {
String decryptedText=null;
try {
cipher.init(Cipher.DECRYPT_MODE, key);
BASE64Decoder base64decoder = new BASE64Decoder();
byte[] encryptedText = base64decoder.decodeBuffer(encryptedString);
byte[] plainText = cipher.doFinal(encryptedText);
decryptedText= bytes2String(plainText);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedText;
}
private static String bytes2String(byte[] bytes) {
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
stringBuffer.append((char) bytes[i]);
}
return stringBuffer.toString();
}
/**
* Testing the DES Encryption And Decryption Technique
*/
public static void main(String args []) throws Exception
{
DESEncryption myEncryptor= new DESEncryption();
String stringToEncrypt="Sanjaal.com";
String encrypted=myEncryptor.encrypt(stringToEncrypt);
String decrypted=myEncryptor.decrypt(encrypted);
System.out.println("String To Encrypt: "+stringToEncrypt);
System.out.println("Encrypted Value :" + encrypted);
System.out.println("Decrypted Value :"+decrypted);
}
}
On the server side, the encyption/decryption of the password field is done in C#.
Now, i need to implement same functionality in my android application. So, i followed this tutorial: http://ttux.net/post/3des-java-encrypter-des-java-encryption/ as below:
import java.security.MessageDigest;
import java.security.spec.KeySpec;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import org.apache.commons.codec.binary.Base64;
public class Encrypter {
private KeySpec keySpec;
private SecretKey key;
private IvParameterSpec iv;
public Encrypter(String keyString, String ivString) {
try {
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest(Base64.decodeBase64(keyString.getBytes("utf-8")));
final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
keySpec = new DESedeKeySpec(keyBytes);
key = SecretKeyFactory.getInstance("DESede").generateSecret(keySpec);
iv = new IvParameterSpec(ivString.getBytes());
} catch(Exception e) {
e.printStackTrace();
}
}
public String encrypt(String value) {
try {
Cipher ecipher = Cipher.getInstance("DESede/CBC/PKCS5Padding","SunJCE");
ecipher.init(Cipher.ENCRYPT_MODE, key, iv);
if(value==null)
return null;
// Encode the string into bytes using utf-8
byte[] utf8 = value.getBytes("UTF8");
// Encrypt
byte[] enc = ecipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return new String(Base64.encodeBase64(enc),"UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String decrypt(String value) {
try {
Cipher dcipher = Cipher.getInstance("DESede/CBC/PKCS5Padding","SunJCE");
dcipher.init(Cipher.DECRYPT_MODE, key, iv);
if(value==null)
return null;
// Decode base64 to get bytes
byte[] dec = Base64.decodeBase64(value.getBytes());
// Decrypt
byte[] utf8 = dcipher.doFinal(dec);
// Decode using utf-8
return new String(utf8, "UTF8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
but i dont know what values i need to provide for KeyValue and ivValue for the above code. Please help me...
Use this code to encrypt your string
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import android.util.Base64;
//string encryption
public class EncryptionHelper {
// Encrypts string and encode in Base64
public static String encryptText(String plainText) throws Exception {
// ---- Use specified 3DES key and IV from other source --------------
byte[] plaintext = plainText.getBytes();//input
byte[] tdesKeyData = Constants.getKey().getBytes();// your encryption key
byte[] myIV = Constants.getInitializationVector().getBytes();// initialization vector
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);
String encryptedString = Base64.encodeToString(cipherText,
Base64.DEFAULT);
// return Base64Coder.encodeString(new String(cipherText));
return encryptedString;
}
}
This is how you can encrypt the string
String encryptedPassword = EncryptionHelper.encryptText(edtText.getText().toString());
EDIT
Code for Constants.java
Class Constants {
private final String initializationVector = "INITALIZATION_VECTOR";
private final String ecnryptionKey = "ENCRYPTION_KEY";
public static String getInitializationVector() {
return initializationVector;
}
public static String getKey() {
return ecnryptionKey;
}
}
Triple DES is called "DESede" (DES using single DES Encrypt, Decrypt, Encrypt for encryption) in both Java and Android runtimes. So it is build in functionality which can be access through the Cipher class. It also lists the available algorithms. For triple DES you could use "DESede/CBC/PKCS5Padding"`. Don't forget to supply it a random IV of 8 bytes.
Triple DES should only be used for backwards compatibility. If you decide to use it at least supply it 24 bytes of key material, otherwise there is a chance that your ciphertext can be cracked. For a more modern approach use AES, preferably in an authenticated mode such as GCM ("AES/GCM/NoPadding"). Note that GCM requires a unique nonce of 12 bytes.