JAVA 到 PHP 7 加密
JAVA to PHP 7 Encryption
我想将 encryption/decryption 从 JAVA 复制到 PHP。但我的问题是结果不匹配。我不知道 java 所以我试图理解 java 中的每一行代码并写入 PHP。
JAVA
secretkey: thisisasecretkey
import java.security.MessageDigest;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class TDESEncrypter {
public String _encrypt(String message, String secretKey) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainTextBytes = message.getBytes("utf-8");
byte[] buf = cipher.doFinal(plainTextBytes);
byte [] base64Bytes = Base64.encodeBase64(buf);
String base64EncryptedString = new String(base64Bytes);
return base64EncryptedString;
}
public String _decrypt(String encryptedText, String secretKey) throws Exception {
byte[] message = Base64.decodeBase64(encryptedText.getBytes("utf-8"));
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
Cipher decipher = Cipher.getInstance("DESede");
decipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = decipher.doFinal(message);
return new String(plainText, "UTF-8");
}
}
以下是使用 java 的步骤,可能有助于复制 PHP 中的函数。
- 使用 sha1 创建散列
- 使用 utf-8 编码将密钥(从凭据)转换为字节数组
- 用 xeroes 填充步骤 2,用零截断或填充(如果需要),使副本具有指定的长度 24
使用 DESede
使用步骤 3 中的密钥字节初始化 Secretkey
使用 DESede 实例创建密码
- 使用第 4 步中的密钥加密模式初始化密码
- 将数据(username/password)转换为使用 utf-8 编码加密的字节数组
- 使用第 6 步密码对第 7 步进行加密
- 以 base 64 格式对 step8 进行编码
- 将 step9 转换为字符串以获得最终的字符串加密消息
到目前为止我做了什么,
function encrypt($data, $secret) {
$key = sha1(utf8_encode($secret), true); <-- Step 1 & 2
$iv = utf8_encode("jvz8bUAx"); <-- Do I use initialise vector on it?
$key .= substr($key, 0, 8);
$method = 'des-ede3-cbc'; //<-- Is this cypher method correct from the above?
if (strlen($data) % 8) {
$data = str_pad($data, strlen($data) + 8 - strlen($data) % 8, "[=13=]");
}
$encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); //Force zero padding.
$encrypted = urlencode(base64_encode($encrypted)); // Added the urlencode.....
return $encrypted;
}
在 Java 代码中,加密算法指定为 DESede
。这对应于 DESede/ECB/PKCS5Padding
,即使用 ECB 模式和 PKCS5 填充。这意味着 PHP-代码:
des-ede3
必须申请
- 必须删除与 IV 相关的所有代码部分(因为 ECB 模式不使用 IV)
- 必须删除自定义填充(绝不是 PKCS5-Padding)(因为
openssl_encrypt
默认使用 PKCS5 填充)
在 Java 代码中,SHA1 哈希(大小为 20 字节)通过附加 0 值扩展到 24 字节。此扩展也必须在 PHP 代码中完成。
PHP-Java_encrypt
-方法的可能对应方法是:
function encrypt($data, $secret) {
$key = sha1(mb_convert_encoding($secret, "UTF-8"), true); // Create SHA-1 hash (20 byte)
$key = str_pad($key, 24, "[=10=]"); // Extend to 24 byte by appending 0-values (would also happen automatically on openssl_encrypt-call)
$encrypted = openssl_encrypt($data, 'DES-EDE3', $key, OPENSSL_RAW_DATA); // Encryption: DESede (24 byte key), ECB-mode, PKCS5-Padding
return base64_encode($encrypted); // Base64-encoding
}
最后:Java-代码有很多缺点,例如
- 使用了三重 DES。更好的选择是 AES,例如参见here
- 使用了 ECB 模式,这本身是不安全的,参见例如here。更好的选择是 CBC 或 GCM(后者在 AES 下)。
- SHA-1 被用作 KDF(它给出了一个太短的密钥,20 个字节而不是实际需要的 24 个字节)。更好的选择是 PBKDF2.
后者只是为了完整性,因为它可能是遗留代码,无论出于何种原因都无法更改。
我想将 encryption/decryption 从 JAVA 复制到 PHP。但我的问题是结果不匹配。我不知道 java 所以我试图理解 java 中的每一行代码并写入 PHP。
JAVA
secretkey: thisisasecretkey
import java.security.MessageDigest;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class TDESEncrypter {
public String _encrypt(String message, String secretKey) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainTextBytes = message.getBytes("utf-8");
byte[] buf = cipher.doFinal(plainTextBytes);
byte [] base64Bytes = Base64.encodeBase64(buf);
String base64EncryptedString = new String(base64Bytes);
return base64EncryptedString;
}
public String _decrypt(String encryptedText, String secretKey) throws Exception {
byte[] message = Base64.decodeBase64(encryptedText.getBytes("utf-8"));
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
Cipher decipher = Cipher.getInstance("DESede");
decipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = decipher.doFinal(message);
return new String(plainText, "UTF-8");
}
}
以下是使用 java 的步骤,可能有助于复制 PHP 中的函数。
- 使用 sha1 创建散列
- 使用 utf-8 编码将密钥(从凭据)转换为字节数组
- 用 xeroes 填充步骤 2,用零截断或填充(如果需要),使副本具有指定的长度 24
使用 DESede
使用步骤 3 中的密钥字节初始化 Secretkey
使用 DESede 实例创建密码
- 使用第 4 步中的密钥加密模式初始化密码
- 将数据(username/password)转换为使用 utf-8 编码加密的字节数组
- 使用第 6 步密码对第 7 步进行加密
- 以 base 64 格式对 step8 进行编码
- 将 step9 转换为字符串以获得最终的字符串加密消息
到目前为止我做了什么,
function encrypt($data, $secret) {
$key = sha1(utf8_encode($secret), true); <-- Step 1 & 2
$iv = utf8_encode("jvz8bUAx"); <-- Do I use initialise vector on it?
$key .= substr($key, 0, 8);
$method = 'des-ede3-cbc'; //<-- Is this cypher method correct from the above?
if (strlen($data) % 8) {
$data = str_pad($data, strlen($data) + 8 - strlen($data) % 8, "[=13=]");
}
$encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); //Force zero padding.
$encrypted = urlencode(base64_encode($encrypted)); // Added the urlencode.....
return $encrypted;
}
在 Java 代码中,加密算法指定为 DESede
。这对应于 DESede/ECB/PKCS5Padding
,即使用 ECB 模式和 PKCS5 填充。这意味着 PHP-代码:
des-ede3
必须申请- 必须删除与 IV 相关的所有代码部分(因为 ECB 模式不使用 IV)
- 必须删除自定义填充(绝不是 PKCS5-Padding)(因为
openssl_encrypt
默认使用 PKCS5 填充)
在 Java 代码中,SHA1 哈希(大小为 20 字节)通过附加 0 值扩展到 24 字节。此扩展也必须在 PHP 代码中完成。
PHP-Java_encrypt
-方法的可能对应方法是:
function encrypt($data, $secret) {
$key = sha1(mb_convert_encoding($secret, "UTF-8"), true); // Create SHA-1 hash (20 byte)
$key = str_pad($key, 24, "[=10=]"); // Extend to 24 byte by appending 0-values (would also happen automatically on openssl_encrypt-call)
$encrypted = openssl_encrypt($data, 'DES-EDE3', $key, OPENSSL_RAW_DATA); // Encryption: DESede (24 byte key), ECB-mode, PKCS5-Padding
return base64_encode($encrypted); // Base64-encoding
}
最后:Java-代码有很多缺点,例如
- 使用了三重 DES。更好的选择是 AES,例如参见here
- 使用了 ECB 模式,这本身是不安全的,参见例如here。更好的选择是 CBC 或 GCM(后者在 AES 下)。
- SHA-1 被用作 KDF(它给出了一个太短的密钥,20 个字节而不是实际需要的 24 个字节)。更好的选择是 PBKDF2.
后者只是为了完整性,因为它可能是遗留代码,无论出于何种原因都无法更改。