使用 Java 解密 OpenSSL PEM 编码的 RSA 私钥?
Decrypting an OpenSSL PEM Encoded RSA private key with Java?
我有一个加密的私钥,我知道密码。
我需要使用 Java 库对其进行解密。
不过我不想使用 BouncyCastle,除非别无选择。根据以往的经验,变化太大,文档不够。
私钥是这样的形式:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,56F3A98D9CFFA77A
X5h7SUDStF1tL16lRM+AfZb1UBDQ0D1YbQ6vmIlXiK....
.....
/KK5CZmIGw==
-----END RSA PRIVATE KEY-----
我认为关键数据是 Base64 编码的,因为我在 64 个字符后看到 \r\n
。
我尝试了以下方法来解密密钥:
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.crypto.EncryptedPrivateKeyInfo;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
public String decrypt(String keyDataStr, String passwordStr){
// This key data start from "X5... to =="
char [] password=passwordStr.toCharArray();
byte [] keyDataBytes=com.sun.jersey.core.util.Base64.decode(keyDataStr);
PBEKeySpec pbeSpec = new PBEKeySpec(password);
EncryptedPrivateKeyInfo pkinfo = new EncryptedPrivateKeyInfo(keyDataBytes);
SecretKeyFactory skf = SecretKeyFactory.getInstance(pkinfo.getAlgName());
Key secret = skf.generateSecret(pbeSpec);
PKCS8EncodedKeySpec keySpec = pkinfo.getKeySpec(secret);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey pk=kf.generatePrivate(keySpec);
return pk.toString();
}
我得到这个异常
java.io.IOException: DerInputStream.getLength(): lengthTag=50, too big.
at sun.security.util.DerInputStream.getLength(DerInputStream.java:561)
at sun.security.util.DerValue.init(DerValue.java:365)
at sun.security.util.DerValue.<init>(DerValue.java:294)
at javax.crypto.EncryptedPrivateKeyInfo.<init> (EncryptedPrivateKeyInfo.java:84)
我是否将正确的参数传递给 EncryptedPrivateKeyInfo
构造函数?
我怎样才能使这个工作?
我尝试了 Ericsonn 的建议,因为我在工作 Java 7,我做了一个小改动,我无法使用 Base64.getMimeCoder() 而是使用 Base64.decode,我得到了这个错误
当在 com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:750)
处使用填充密码解密时,我收到这样的错误 Input length must be multiple of 8
static RSAPrivateKey decrypt(String keyDataStr, String ivHex, String password)
throws GeneralSecurityException, UnsupportedEncodingException
{
byte[] pw = password.getBytes(StandardCharsets.UTF_8);
byte[] iv = h2b(ivHex);
SecretKey secret = opensslKDF(pw, iv);
Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
byte [] keyBytes=Base64.decode(keyDataStr.getBytes("UTF-8"));
byte[] pkcs1 = cipher.doFinal(keyBytes);
/* See note for definition of "decodeRSAPrivatePKCS1" */
RSAPrivateCrtKeySpec spec = decodeRSAPrivatePKCS1(pkcs1);
KeyFactory rsa = KeyFactory.getInstance("RSA");
return (RSAPrivateKey) rsa.generatePrivate(spec);
}
private static SecretKey opensslKDF(byte[] pw, byte[] iv)
throws NoSuchAlgorithmException
{
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(pw);
md5.update(iv);
byte[] d0 = md5.digest();
md5.update(d0);
md5.update(pw);
md5.update(iv);
byte[] d1 = md5.digest();
byte[] key = new byte[24];
System.arraycopy(d0, 0, key, 0, 16);
System.arraycopy(d1, 0, key, 16, 8);
return new SecretKeySpec(key, "DESede");
}
private static byte[] h2b(CharSequence s)
{
int len = s.length();
byte[] b = new byte[len / 2];
for (int src = 0, dst = 0; src < len; ++dst) {
int hi = Character.digit(s.charAt(src++), 16);
int lo = Character.digit(s.charAt(src++), 16);
b[dst] = (byte) (hi << 4 | lo);
}
return b;
}
static RSAPrivateCrtKeySpec decodeRSAPrivatePKCS1(byte[] encoded)
{
ByteBuffer input = ByteBuffer.wrap(encoded);
if (der(input, 0x30) != input.remaining())
throw new IllegalArgumentException("Excess data");
if (!BigInteger.ZERO.equals(derint(input)))
throw new IllegalArgumentException("Unsupported version");
BigInteger n = derint(input);
BigInteger e = derint(input);
BigInteger d = derint(input);
BigInteger p = derint(input);
BigInteger q = derint(input);
BigInteger ep = derint(input);
BigInteger eq = derint(input);
BigInteger c = derint(input);
return new RSAPrivateCrtKeySpec(n, e, d, p, q, ep, eq, c);
}
private static BigInteger derint(ByteBuffer input)
{
byte[] value = new byte[der(input, 0x02)];
input.get(value);
return new BigInteger(+1, value);
}
private static int der(ByteBuffer input, int exp)
{
int tag = input.get() & 0xFF;
if (tag != exp)
throw new IllegalArgumentException("Unexpected tag");
int n = input.get() & 0xFF;
if (n < 128)
return n;
n &= 0x7F;
if ((n < 1) || (n > 2))
throw new IllegalArgumentException("Invalid length");
int len = 0;
while (n-- > 0) {
len <<= 8;
len |= input.get() & 0xFF;
}
return len;
}
1640 是 keyDataStr.length() 而 1228 是 keyBytes.length
您需要使用 non-standard、OpenSSL 方法来导出解密密钥。然后使用它来解密 PKCS-#1 编码的密钥——您正在使用的是 而不是 PKCS #8 信封。您还需要 header 中的 IV 作为这些过程的输入。
看起来像这样:
static RSAPrivateKey decrypt(String keyDataStr, String ivHex, String password)
throws GeneralSecurityException
{
byte[] pw = password.getBytes(StandardCharsets.UTF_8);
byte[] iv = h2b(ivHex);
SecretKey secret = opensslKDF(pw, iv);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
byte[] pkcs1 = cipher.doFinal(Base64.getMimeDecoder().decode(keyDataStr));
/* See note for definition of "decodeRSAPrivatePKCS1" */
RSAPrivateCrtKeySpec spec = decodeRSAPrivatePKCS1(pkcs1);
KeyFactory rsa = KeyFactory.getInstance("RSA");
return (RSAPrivateKey) rsa.generatePrivate(spec);
}
private static SecretKey opensslKDF(byte[] pw, byte[] iv)
throws NoSuchAlgorithmException
{
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(pw);
md5.update(iv);
byte[] d0 = md5.digest();
md5.update(d0);
md5.update(pw);
md5.update(iv);
byte[] d1 = md5.digest();
byte[] key = new byte[24];
System.arraycopy(d0, 0, key, 0, 16);
System.arraycopy(d1, 0, key, 16, 8);
return new SecretKeySpec(key, "DESede");
}
private static byte[] h2b(CharSequence s)
{
int len = s.length();
byte[] b = new byte[len / 2];
for (int src = 0, dst = 0; src < len; ++dst) {
int hi = Character.digit(s.charAt(src++), 16);
int lo = Character.digit(s.charAt(src++), 16);
b[dst] = (byte) (hi << 4 | lo);
}
return b;
}
这已经是很多代码了,所以我将 link 到另一个答案来定义 the decodeRSAPrivatePKCS1()
method.
Java 下面的代码示例显示了如何构造解密密钥以从使用 openssl 1.0.x genrsa 命令创建的加密私钥中获取基础 RSA 密钥;具体来自以下可能已被利用的 genrsa 选项:
-des encrypt the generated key with DES in cbc mode
-des3 encrypt the generated key with DES in ede cbc mode (168 bit key)
-aes128, -aes192, -aes256 encrypt PEM output with cbc aes
以上选项会生成格式为 ...
的加密 RSA 私钥
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AAA,BBB
...
其中 AAA 是以下之一:
DES-CBC, DES-EDE3-CBC, AES-128-CBC, AES-192-CBC, AES-256-CBC
AND BBB 是十六进制编码的 IV 值
KeyFactory factory = KeyFactory.getInstance("RSA");
KeySpec keySpec = null;
RSAPrivateKey privateKey = null;
Matcher matcher = OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_PATTERN.matcher(pemContents);
if (matcher.matches())
{
String encryptionDetails = matcher.group(1).trim(); // e.g. AES-256-CBC,XXXXXXX
String encryptedKey = matcher.group(2).replaceAll("\s", ""); // remove tabs / spaces / newlines / carriage return etc
System.out.println("PEM appears to be OpenSSL Encrypted RSA Private Key; Encryption details : "
+ encryptionDetails + "; Key : " + encryptedKey);
byte[] encryptedBinaryKey = java.util.Base64.getDecoder().decode(encryptedKey);
String[] encryptionDetailsParts = encryptionDetails.split(",");
if (encryptionDetailsParts.length == 2)
{
String encryptionAlgorithm = encryptionDetailsParts[0];
String encryptedAlgorithmParams = encryptionDetailsParts[1]; // i.e. the initialization vector in hex
byte[] pw = new String(password).getBytes(StandardCharsets.UTF_8);
byte[] iv = fromHex(encryptedAlgorithmParams);
MessageDigest digest = MessageDigest.getInstance("MD5");
// we need to come up with the encryption key
// first round digest based on password and first 8-bytes of IV ..
digest.update(pw);
digest.update(iv, 0, 8);
byte[] round1Digest = digest.digest(); // The digest is reset after this call is made.
// second round digest based on first round digest, password, and first 8-bytes of IV ...
digest.update(round1Digest);
digest.update(pw);
digest.update(iv, 0, 8);
byte[] round2Digest = digest.digest();
Cipher cipher = null;
SecretKey secretKey = null;
byte[] key = null;
byte[] pkcs1 = null;
if ("AES-256-CBC".equals(encryptionAlgorithm))
{
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
key = new byte[32]; // 256 bit key (block size still 128-bit)
System.arraycopy(round1Digest, 0, key, 0, 16);
System.arraycopy(round2Digest, 0, key, 16, 16);
secretKey = new SecretKeySpec(key, "AES");
}
else if ("AES-192-CBC".equals(encryptionAlgorithm))
{
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
key = new byte[24]; // key size of 24 bytes
System.arraycopy(round1Digest, 0, key, 0, 16);
System.arraycopy(round2Digest, 0, key, 16, 8);
secretKey = new SecretKeySpec(key, "AES");
}
else if ("AES-128-CBC".equals(encryptionAlgorithm))
{
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
key = new byte[16]; // 128 bit key
System.arraycopy(round1Digest, 0, key, 0, 16);
secretKey = new SecretKeySpec(key, "AES");
}
else if ("DES-EDE3-CBC".equals(encryptionAlgorithm))
{
cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
key = new byte[24]; // key size of 24 bytes
System.arraycopy(round1Digest, 0, key, 0, 16);
System.arraycopy(round2Digest, 0, key, 16, 8);
secretKey = new SecretKeySpec(key, "DESede");
}
else if ("DES-CBC".equals(encryptionAlgorithm))
{
cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
key = new byte[8]; // key size of 8 bytes
System.arraycopy(round1Digest, 0, key, 0, 8);
secretKey = new SecretKeySpec(key, "DES");
}
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
pkcs1 = cipher.doFinal(encryptedBinaryKey);
keySpec = pkcs1ParsePrivateKey(pkcs1);
privateKey = (RSAPrivateKey) factory.generatePrivate(keySpec);
}
}
正则表达式 ...
static final String OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_REGEX = "\s*"
+ "-----BEGIN RSA PUBLIC KEY-----" + "\s*"
+ "Proc-Type: 4,ENCRYPTED" + "\s*"
+ "DEK-Info:" + "\s*([^\s]+)" + "\s+"
+ "([\s\S]*)"
+ "-----END RSA PUBLIC KEY-----" + "\s*";
static final Pattern OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_PATTERN = Pattern.compile(OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_REGEX);
fromHex(...) 方法 ...
public static byte[] fromHex(String hexString)
{
byte[] bytes = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i += 2)
{
bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
+ Character.digit(hexString.charAt(i + 1), 16));
}
return bytes;
}
我有一个加密的私钥,我知道密码。
我需要使用 Java 库对其进行解密。
不过我不想使用 BouncyCastle,除非别无选择。根据以往的经验,变化太大,文档不够。
私钥是这样的形式:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,56F3A98D9CFFA77A
X5h7SUDStF1tL16lRM+AfZb1UBDQ0D1YbQ6vmIlXiK....
.....
/KK5CZmIGw==
-----END RSA PRIVATE KEY-----
我认为关键数据是 Base64 编码的,因为我在 64 个字符后看到 \r\n
。
我尝试了以下方法来解密密钥:
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.crypto.EncryptedPrivateKeyInfo;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
public String decrypt(String keyDataStr, String passwordStr){
// This key data start from "X5... to =="
char [] password=passwordStr.toCharArray();
byte [] keyDataBytes=com.sun.jersey.core.util.Base64.decode(keyDataStr);
PBEKeySpec pbeSpec = new PBEKeySpec(password);
EncryptedPrivateKeyInfo pkinfo = new EncryptedPrivateKeyInfo(keyDataBytes);
SecretKeyFactory skf = SecretKeyFactory.getInstance(pkinfo.getAlgName());
Key secret = skf.generateSecret(pbeSpec);
PKCS8EncodedKeySpec keySpec = pkinfo.getKeySpec(secret);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey pk=kf.generatePrivate(keySpec);
return pk.toString();
}
我得到这个异常
java.io.IOException: DerInputStream.getLength(): lengthTag=50, too big.
at sun.security.util.DerInputStream.getLength(DerInputStream.java:561)
at sun.security.util.DerValue.init(DerValue.java:365)
at sun.security.util.DerValue.<init>(DerValue.java:294)
at javax.crypto.EncryptedPrivateKeyInfo.<init> (EncryptedPrivateKeyInfo.java:84)
我是否将正确的参数传递给 EncryptedPrivateKeyInfo
构造函数?
我怎样才能使这个工作?
我尝试了 Ericsonn 的建议,因为我在工作 Java 7,我做了一个小改动,我无法使用 Base64.getMimeCoder() 而是使用 Base64.decode,我得到了这个错误 当在 com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:750)
处使用填充密码解密时,我收到这样的错误 Input length must be multiple of 8static RSAPrivateKey decrypt(String keyDataStr, String ivHex, String password)
throws GeneralSecurityException, UnsupportedEncodingException
{
byte[] pw = password.getBytes(StandardCharsets.UTF_8);
byte[] iv = h2b(ivHex);
SecretKey secret = opensslKDF(pw, iv);
Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
byte [] keyBytes=Base64.decode(keyDataStr.getBytes("UTF-8"));
byte[] pkcs1 = cipher.doFinal(keyBytes);
/* See note for definition of "decodeRSAPrivatePKCS1" */
RSAPrivateCrtKeySpec spec = decodeRSAPrivatePKCS1(pkcs1);
KeyFactory rsa = KeyFactory.getInstance("RSA");
return (RSAPrivateKey) rsa.generatePrivate(spec);
}
private static SecretKey opensslKDF(byte[] pw, byte[] iv)
throws NoSuchAlgorithmException
{
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(pw);
md5.update(iv);
byte[] d0 = md5.digest();
md5.update(d0);
md5.update(pw);
md5.update(iv);
byte[] d1 = md5.digest();
byte[] key = new byte[24];
System.arraycopy(d0, 0, key, 0, 16);
System.arraycopy(d1, 0, key, 16, 8);
return new SecretKeySpec(key, "DESede");
}
private static byte[] h2b(CharSequence s)
{
int len = s.length();
byte[] b = new byte[len / 2];
for (int src = 0, dst = 0; src < len; ++dst) {
int hi = Character.digit(s.charAt(src++), 16);
int lo = Character.digit(s.charAt(src++), 16);
b[dst] = (byte) (hi << 4 | lo);
}
return b;
}
static RSAPrivateCrtKeySpec decodeRSAPrivatePKCS1(byte[] encoded)
{
ByteBuffer input = ByteBuffer.wrap(encoded);
if (der(input, 0x30) != input.remaining())
throw new IllegalArgumentException("Excess data");
if (!BigInteger.ZERO.equals(derint(input)))
throw new IllegalArgumentException("Unsupported version");
BigInteger n = derint(input);
BigInteger e = derint(input);
BigInteger d = derint(input);
BigInteger p = derint(input);
BigInteger q = derint(input);
BigInteger ep = derint(input);
BigInteger eq = derint(input);
BigInteger c = derint(input);
return new RSAPrivateCrtKeySpec(n, e, d, p, q, ep, eq, c);
}
private static BigInteger derint(ByteBuffer input)
{
byte[] value = new byte[der(input, 0x02)];
input.get(value);
return new BigInteger(+1, value);
}
private static int der(ByteBuffer input, int exp)
{
int tag = input.get() & 0xFF;
if (tag != exp)
throw new IllegalArgumentException("Unexpected tag");
int n = input.get() & 0xFF;
if (n < 128)
return n;
n &= 0x7F;
if ((n < 1) || (n > 2))
throw new IllegalArgumentException("Invalid length");
int len = 0;
while (n-- > 0) {
len <<= 8;
len |= input.get() & 0xFF;
}
return len;
}
1640 是 keyDataStr.length() 而 1228 是 keyBytes.length
您需要使用 non-standard、OpenSSL 方法来导出解密密钥。然后使用它来解密 PKCS-#1 编码的密钥——您正在使用的是 而不是 PKCS #8 信封。您还需要 header 中的 IV 作为这些过程的输入。
看起来像这样:
static RSAPrivateKey decrypt(String keyDataStr, String ivHex, String password)
throws GeneralSecurityException
{
byte[] pw = password.getBytes(StandardCharsets.UTF_8);
byte[] iv = h2b(ivHex);
SecretKey secret = opensslKDF(pw, iv);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
byte[] pkcs1 = cipher.doFinal(Base64.getMimeDecoder().decode(keyDataStr));
/* See note for definition of "decodeRSAPrivatePKCS1" */
RSAPrivateCrtKeySpec spec = decodeRSAPrivatePKCS1(pkcs1);
KeyFactory rsa = KeyFactory.getInstance("RSA");
return (RSAPrivateKey) rsa.generatePrivate(spec);
}
private static SecretKey opensslKDF(byte[] pw, byte[] iv)
throws NoSuchAlgorithmException
{
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(pw);
md5.update(iv);
byte[] d0 = md5.digest();
md5.update(d0);
md5.update(pw);
md5.update(iv);
byte[] d1 = md5.digest();
byte[] key = new byte[24];
System.arraycopy(d0, 0, key, 0, 16);
System.arraycopy(d1, 0, key, 16, 8);
return new SecretKeySpec(key, "DESede");
}
private static byte[] h2b(CharSequence s)
{
int len = s.length();
byte[] b = new byte[len / 2];
for (int src = 0, dst = 0; src < len; ++dst) {
int hi = Character.digit(s.charAt(src++), 16);
int lo = Character.digit(s.charAt(src++), 16);
b[dst] = (byte) (hi << 4 | lo);
}
return b;
}
这已经是很多代码了,所以我将 link 到另一个答案来定义 the decodeRSAPrivatePKCS1()
method.
Java 下面的代码示例显示了如何构造解密密钥以从使用 openssl 1.0.x genrsa 命令创建的加密私钥中获取基础 RSA 密钥;具体来自以下可能已被利用的 genrsa 选项:
-des encrypt the generated key with DES in cbc mode
-des3 encrypt the generated key with DES in ede cbc mode (168 bit key)
-aes128, -aes192, -aes256 encrypt PEM output with cbc aes
以上选项会生成格式为 ...
的加密 RSA 私钥-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AAA,BBB
...
其中 AAA 是以下之一:
DES-CBC, DES-EDE3-CBC, AES-128-CBC, AES-192-CBC, AES-256-CBC
AND BBB 是十六进制编码的 IV 值
KeyFactory factory = KeyFactory.getInstance("RSA");
KeySpec keySpec = null;
RSAPrivateKey privateKey = null;
Matcher matcher = OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_PATTERN.matcher(pemContents);
if (matcher.matches())
{
String encryptionDetails = matcher.group(1).trim(); // e.g. AES-256-CBC,XXXXXXX
String encryptedKey = matcher.group(2).replaceAll("\s", ""); // remove tabs / spaces / newlines / carriage return etc
System.out.println("PEM appears to be OpenSSL Encrypted RSA Private Key; Encryption details : "
+ encryptionDetails + "; Key : " + encryptedKey);
byte[] encryptedBinaryKey = java.util.Base64.getDecoder().decode(encryptedKey);
String[] encryptionDetailsParts = encryptionDetails.split(",");
if (encryptionDetailsParts.length == 2)
{
String encryptionAlgorithm = encryptionDetailsParts[0];
String encryptedAlgorithmParams = encryptionDetailsParts[1]; // i.e. the initialization vector in hex
byte[] pw = new String(password).getBytes(StandardCharsets.UTF_8);
byte[] iv = fromHex(encryptedAlgorithmParams);
MessageDigest digest = MessageDigest.getInstance("MD5");
// we need to come up with the encryption key
// first round digest based on password and first 8-bytes of IV ..
digest.update(pw);
digest.update(iv, 0, 8);
byte[] round1Digest = digest.digest(); // The digest is reset after this call is made.
// second round digest based on first round digest, password, and first 8-bytes of IV ...
digest.update(round1Digest);
digest.update(pw);
digest.update(iv, 0, 8);
byte[] round2Digest = digest.digest();
Cipher cipher = null;
SecretKey secretKey = null;
byte[] key = null;
byte[] pkcs1 = null;
if ("AES-256-CBC".equals(encryptionAlgorithm))
{
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
key = new byte[32]; // 256 bit key (block size still 128-bit)
System.arraycopy(round1Digest, 0, key, 0, 16);
System.arraycopy(round2Digest, 0, key, 16, 16);
secretKey = new SecretKeySpec(key, "AES");
}
else if ("AES-192-CBC".equals(encryptionAlgorithm))
{
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
key = new byte[24]; // key size of 24 bytes
System.arraycopy(round1Digest, 0, key, 0, 16);
System.arraycopy(round2Digest, 0, key, 16, 8);
secretKey = new SecretKeySpec(key, "AES");
}
else if ("AES-128-CBC".equals(encryptionAlgorithm))
{
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
key = new byte[16]; // 128 bit key
System.arraycopy(round1Digest, 0, key, 0, 16);
secretKey = new SecretKeySpec(key, "AES");
}
else if ("DES-EDE3-CBC".equals(encryptionAlgorithm))
{
cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
key = new byte[24]; // key size of 24 bytes
System.arraycopy(round1Digest, 0, key, 0, 16);
System.arraycopy(round2Digest, 0, key, 16, 8);
secretKey = new SecretKeySpec(key, "DESede");
}
else if ("DES-CBC".equals(encryptionAlgorithm))
{
cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
key = new byte[8]; // key size of 8 bytes
System.arraycopy(round1Digest, 0, key, 0, 8);
secretKey = new SecretKeySpec(key, "DES");
}
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
pkcs1 = cipher.doFinal(encryptedBinaryKey);
keySpec = pkcs1ParsePrivateKey(pkcs1);
privateKey = (RSAPrivateKey) factory.generatePrivate(keySpec);
}
}
正则表达式 ...
static final String OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_REGEX = "\s*"
+ "-----BEGIN RSA PUBLIC KEY-----" + "\s*"
+ "Proc-Type: 4,ENCRYPTED" + "\s*"
+ "DEK-Info:" + "\s*([^\s]+)" + "\s+"
+ "([\s\S]*)"
+ "-----END RSA PUBLIC KEY-----" + "\s*";
static final Pattern OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_PATTERN = Pattern.compile(OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_REGEX);
fromHex(...) 方法 ...
public static byte[] fromHex(String hexString)
{
byte[] bytes = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i += 2)
{
bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
+ Character.digit(hexString.charAt(i + 1), 16));
}
return bytes;
}