Java mcrypt_encrypt PHP 函数代码 MCRYPT_RIJNDAEL_256 密码
Java code for mcrypt_encrypt PHP function with MCRYPT_RIJNDAEL_256 cipher
我有一个 PHP 代码用于加密字符串(令牌)。我需要生成此令牌并调用遗留后端 API。后端 API 在允许访问 API 之前对其进行解密和验证。我们正在 Java 构建客户端应用程序。所以这段代码需要在Java.
中实现
$stringToEncode="****String which needs to be encrypted. This string length is multiple of 32********************";
$key="32ByteKey-asdcxzasdsadasdasdasda";
echo base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_256,
$key,
$stringToEncode,
MCRYPT_MODE_CBC,
$key
)
);
此处IV与key相同。
我尝试使用以下 Java 代码使用“org.bouncycastle.crypto”
private static void encrypt(String key, String data) throws InvalidCipherTextException {
byte[] givenKey = key.getBytes(Charset.forName("ASCII"));
final int keysize = 256;
byte[] keyData = new byte[keysize / Byte.SIZE];
System.arraycopy(givenKey, 0, keyData, 0, Math.min(givenKey.length, keyData.length));
KeyParameter keyParameter = new KeyParameter(keyData);
BlockCipher rijndael = new RijndaelEngine(256);
ZeroBytePadding c = new ZeroBytePadding();
PaddedBufferedBlockCipher pbbc = new PaddedBufferedBlockCipher(rijndael, c);
CipherParameters ivAndKey = new ParametersWithIV(keyParameter, key.getBytes(Charset.forName("ASCII")));
pbbc.init(true, ivAndKey);
byte[] plaintext = data.getBytes(Charset.forName("UTF8"));
byte[] ciphertext = new byte[pbbc.getOutputSize(plaintext.length)];
int offset = 0;
offset += pbbc.processBytes(plaintext, 0, plaintext.length, ciphertext, offset);
offset += pbbc.doFinal(ciphertext, offset);
System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(ciphertext));
}
但低于异常 -
Exception in thread "main" java.lang.IllegalArgumentException: invalid parameter passed to Rijndael init - org.bouncycastle.crypto.params.ParametersWithIV
我什至尝试使用“javax.crypto”,如下所示 -
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class aes{
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
String key = "32ByteKey-asdcxzasdsadasdasdasda";
String data = "****String which needs to be encrypted. This string length is multiple of 32********************";
encrypt(key, data);
}
public static void encrypt(String key1, String data) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{
byte[] key = key1.getBytes(Charset.forName("ASCII"));
byte[] decrypted = data.getBytes(Charset.forName("UTF8"));
IvParameterSpec ivSpec = new IvParameterSpec(key);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), ivSpec);
byte[] encrypted = Base64.getEncoder().encodeToString(cipher.doFinal(decrypted)).getBytes();
System.out.println(encrypted);
}
}
但是出现异常 -
Exception in thread "main" java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long
有人可以建议我如何实现吗?
PHP 代码使用块大小为 256 位的 Rijndael。这不受 SunJCE 提供程序支持,只有 AES(它是 Rindael 的一个子集,块大小为 128 位)。因此,第二个 Java 代码片段也不起作用。因此,必须应用像 BouncyCastle (BC) 这样的第三方提供商。
Java / BC 代码中有两个错误:
- 与 PHP 代码相反,没有应用 CBC。这必须使用
CBCBlockCipher
. 进行更改
- BC 的零填充变体与 mcrypt 变体不同。 BC 变体总是填充,i。 e.即使明文的长度已经对应于块大小的整数倍(此处为 32 字节),mcrypt 变体也不会(即,如果明文的长度不对应于整数倍,后者只会填充blocksize).
由于根据描述,明文已经对应于块大小的整数倍,因此 mcrypt 变体不会填充。在 Java / BC 代码中,如果根本不使用填充,就可以实现这一点。
但要注意:如果明文的长度不对应于块大小的整数倍,当然必须使用填充(关于与 PHP 代码中使用的零填充变体的兼容性)。
这两个问题都可以通过更换线路来解决
ZeroBytePadding c = new ZeroBytePadding();
PaddedBufferedBlockCipher pbbc = new PaddedBufferedBlockCipher(rijndael, c);
来自
BufferedBlockCipher pbbc = new BufferedBlockCipher(new CBCBlockCipher(rijndael));
那么两个密码产生的密文是一样的
一些补充说明:
- 使用密钥作为 IV 通常没有用。由于出于安全原因,对于给定的密钥,IV 只能使用一次,因此必须在此处为每次加密使用新的密钥。另请参阅 here。
通常在实践中会为每次加密生成一个新的随机 IV。
- 通常使用标准更安全,即 AES 而不是块大小为 256 位的 Rijndael,这不是标准。
- 零填充不可靠(此外,有几种变体,如您所见,可能会导致问题)。更靠谱的是PKCS7 padding.
我有一个 PHP 代码用于加密字符串(令牌)。我需要生成此令牌并调用遗留后端 API。后端 API 在允许访问 API 之前对其进行解密和验证。我们正在 Java 构建客户端应用程序。所以这段代码需要在Java.
中实现$stringToEncode="****String which needs to be encrypted. This string length is multiple of 32********************";
$key="32ByteKey-asdcxzasdsadasdasdasda";
echo base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_256,
$key,
$stringToEncode,
MCRYPT_MODE_CBC,
$key
)
);
此处IV与key相同。 我尝试使用以下 Java 代码使用“org.bouncycastle.crypto”
private static void encrypt(String key, String data) throws InvalidCipherTextException {
byte[] givenKey = key.getBytes(Charset.forName("ASCII"));
final int keysize = 256;
byte[] keyData = new byte[keysize / Byte.SIZE];
System.arraycopy(givenKey, 0, keyData, 0, Math.min(givenKey.length, keyData.length));
KeyParameter keyParameter = new KeyParameter(keyData);
BlockCipher rijndael = new RijndaelEngine(256);
ZeroBytePadding c = new ZeroBytePadding();
PaddedBufferedBlockCipher pbbc = new PaddedBufferedBlockCipher(rijndael, c);
CipherParameters ivAndKey = new ParametersWithIV(keyParameter, key.getBytes(Charset.forName("ASCII")));
pbbc.init(true, ivAndKey);
byte[] plaintext = data.getBytes(Charset.forName("UTF8"));
byte[] ciphertext = new byte[pbbc.getOutputSize(plaintext.length)];
int offset = 0;
offset += pbbc.processBytes(plaintext, 0, plaintext.length, ciphertext, offset);
offset += pbbc.doFinal(ciphertext, offset);
System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(ciphertext));
}
但低于异常 -
Exception in thread "main" java.lang.IllegalArgumentException: invalid parameter passed to Rijndael init - org.bouncycastle.crypto.params.ParametersWithIV
我什至尝试使用“javax.crypto”,如下所示 -
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class aes{
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
String key = "32ByteKey-asdcxzasdsadasdasdasda";
String data = "****String which needs to be encrypted. This string length is multiple of 32********************";
encrypt(key, data);
}
public static void encrypt(String key1, String data) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{
byte[] key = key1.getBytes(Charset.forName("ASCII"));
byte[] decrypted = data.getBytes(Charset.forName("UTF8"));
IvParameterSpec ivSpec = new IvParameterSpec(key);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), ivSpec);
byte[] encrypted = Base64.getEncoder().encodeToString(cipher.doFinal(decrypted)).getBytes();
System.out.println(encrypted);
}
}
但是出现异常 -
Exception in thread "main" java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long
有人可以建议我如何实现吗?
PHP 代码使用块大小为 256 位的 Rijndael。这不受 SunJCE 提供程序支持,只有 AES(它是 Rindael 的一个子集,块大小为 128 位)。因此,第二个 Java 代码片段也不起作用。因此,必须应用像 BouncyCastle (BC) 这样的第三方提供商。
Java / BC 代码中有两个错误:
- 与 PHP 代码相反,没有应用 CBC。这必须使用
CBCBlockCipher
. 进行更改
- BC 的零填充变体与 mcrypt 变体不同。 BC 变体总是填充,i。 e.即使明文的长度已经对应于块大小的整数倍(此处为 32 字节),mcrypt 变体也不会(即,如果明文的长度不对应于整数倍,后者只会填充blocksize).
由于根据描述,明文已经对应于块大小的整数倍,因此 mcrypt 变体不会填充。在 Java / BC 代码中,如果根本不使用填充,就可以实现这一点。
但要注意:如果明文的长度不对应于块大小的整数倍,当然必须使用填充(关于与 PHP 代码中使用的零填充变体的兼容性)。
这两个问题都可以通过更换线路来解决
ZeroBytePadding c = new ZeroBytePadding();
PaddedBufferedBlockCipher pbbc = new PaddedBufferedBlockCipher(rijndael, c);
来自
BufferedBlockCipher pbbc = new BufferedBlockCipher(new CBCBlockCipher(rijndael));
那么两个密码产生的密文是一样的
一些补充说明:
- 使用密钥作为 IV 通常没有用。由于出于安全原因,对于给定的密钥,IV 只能使用一次,因此必须在此处为每次加密使用新的密钥。另请参阅 here。
通常在实践中会为每次加密生成一个新的随机 IV。 - 通常使用标准更安全,即 AES 而不是块大小为 256 位的 Rijndael,这不是标准。
- 零填充不可靠(此外,有几种变体,如您所见,可能会导致问题)。更靠谱的是PKCS7 padding.