Как создать RSA PrivateKey из строки с классом RSAPrivateKeySpec в Java?
У меня есть приведенная ниже информация, и я хочу сгенерировать открытый и закрытый ключи в RSA (Java).
String pubKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJXFRUWMDJZ+moC/VbcAXoY5dDxOruwI2B+B+YZRHSRRTKPyd9v0HTqdLeVgufLu/cSxlZAKtZDp9mfgyNdbY9ECAwEAAQ==";
String privKey = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAlcVFRYwMln6agL9VtwBehjl0PE6u7AjYH4H5hlEdJFFMo/J32/QdOp0t5WC58u79xLGVkAq1kOn2Z+DI11tj0QIDAQABAkBC1Bp71OkNAgL47edWWADVja9y9X0R70RYkst/hpQlTrjN4QxzN4k4gCqqdFkno2LfacRO7igMQuVEmYujfkbNAiEA/lU1CyW9J65FXSObsBLxqlNpFw79B2EKUkT6o7b2Ez8CIQCWwJlIyDaoXt7CrvTrPDpok7U93ZKmDPiRjjXDPsGU7wIhAJ6pITIXFO2QNg1ojVNGPiR3bHPKEedsjjfMeF9xYAmZAiAQnfpHg4pC1PJJE2/73g+yJ1X7E8ludE+R+9MBSpGcEQIgBWaVSyTx4e+gSulT93vnMpVsYmiwe53e5t4Uxs+cgSE=";
String nModulusPublic = "AJXFRUWMDJZ-moC_VbcAXoY5dDxOruwI2B-B-YZRHSRRTKPyd9v0HTqdLeVgufLu_cSxlZAKtZDp9mfgyNdbY9E=";
String eExponentPublic = "AQAB";
String nModulusPrivate = "AJXFRUWMDJZ-moC_VbcAXoY5dDxOruwI2B-B-YZRHSRRTKPyd9v0HTqdLeVgufLu_cSxlZAKtZDp9mfgyNdbY9E=";
String eExponentPrivate = "QtQae9TpDQIC-O3nVlgA1Y2vcvV9Ee9EWJLLf4aUJU64zeEMczeJOIAqqnRZJ6Ni32nETu4oDELlRJmLo35GzQ==";
Это основные функции шифрования и дешифрования:
static String Decrypt(String encodedString,PrivateKey privKey) {
try {
Cipher cipher = Cipher.getInstance(cipherInstancename);
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encodedString));
return new String(decrypted, "UTF-8");
} catch (Exception err) {
return err.fillInStackTrace().toString();
}
}
static String Encrypt(String encodedString,PublicKey pubKey) {
try {
Cipher cipher = Cipher.getInstance(cipherInstancename);
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = new String(encodedString).getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);
String encryptedString = Base64.getEncoder().encodeToString(cipherData);
return encryptedString;
} catch (Exception err) {
return err.fillInStackTrace().toString();
}
}
Если я создам PrivateKey и PublicKey с помощью функции ниже, все будет отлично работать:
static PrivateKey firstPrivateKey(String privateKeyStr) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(privateKeyStr.getBytes(StandardCharsets.UTF_8));
PKCS8EncodedKeySpec specPrivate = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey fileGeneratedPrivateKey = keyFactory.generatePrivate(specPrivate);
RSAPrivateKey rsaPrv = (RSAPrivateKey)(fileGeneratedPrivateKey);
return rsaPrv;
}
static PublicKey firstPublicKey(String publicKeyStr) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr.getBytes(StandardCharsets.UTF_8));
X509EncodedKeySpec specPublic = new X509EncodedKeySpec(keyBytes);
PublicKey fileGeneratedPublicKey = keyFactory.generatePublic(specPublic);
RSAPublicKey rsaPub = (RSAPublicKey)(fileGeneratedPublicKey);
return rsaPub;
}
Но я хочу создать их таким образом с помощью функции ниже, но расшифровка не работает:
static PublicKey secondPublicKey(String publicKString,String publicExponentStr) throws Exception {
byte[] modulusBytes = Base64.getDecoder().decode(publicKString);
byte[] exponentBytes = Base64.getDecoder().decode(publicExponentStr);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);
return pubKey;
}
static PrivateKey secondPrivateKey(String privateKString,String privateExponentStr) throws Exception {
byte[] modulusBytes = Base64.getDecoder().decode(privateKString);
byte[] exponentBytes = Base64.getDecoder().decode(privateExponentStr);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPrivateKeySpec privSpec = new RSAPrivateKeySpec(modulus,exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privKey = fact.generatePrivate(privSpec);
return privKey;
}
Использование генераторов ключей firstPrivateKey и firstPublicKey и хорошая работа:
String a = Encrypt("test",firstPrivateKey(pubKey));
String b = Decrypt(a, firstPublicKey(privKey));
System.out.println(b);
Использование вторых функций и не работает:
String a = Encrypt("test",secondPublicKey(pubKey,eExponentPublic));
String b = Decrypt(a, secondPrivateKey(privKey,eExponentPrivate));
System.out.println(b);
В чем проблема с функциями secondPublicKey и secondPrivateKey?
Обновлять:
Я генерирую все ключи и модуль из этого кода, похоже, мое декодирование не в порядке:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
// RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(1024, RSAKeyGenParameterSpec.F4);
kpg.initialize( 512 );
KeyPair kp = kpg.generateKeyPair();
String publicKeyStr = Base64.getEncoder().encodeToString(kp.getPublic().getEncoded());
String privateKeyStr = Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr.getBytes(StandardCharsets.UTF_8));
X509EncodedKeySpec specPublic = new X509EncodedKeySpec(keyBytes);
PublicKey fileGeneratedPublicKey = keyFactory.generatePublic(specPublic);
RSAPublicKey rsaPub = (RSAPublicKey)(fileGeneratedPublicKey);
keyBytes = Base64.getDecoder().decode(privateKeyStr.getBytes(StandardCharsets.UTF_8));
PKCS8EncodedKeySpec specPrivate = new PKCS8EncodedKeySpec(keyBytes);
PrivateKey fileGeneratedPrivateKey = keyFactory.generatePrivate(specPrivate);
RSAPrivateKey rsaPrv = (RSAPrivateKey)(fileGeneratedPrivateKey);
BigInteger publicKeyModulus = rsaPub.getModulus();
BigInteger publicKeyExponent = rsaPub.getPublicExponent();
BigInteger privateKeyModulus = rsaPrv.getModulus();
BigInteger privateKeyExponent = rsaPrv.getPrivateExponent();
String nModulusPublic=Base64.getUrlEncoder().encodeToString(publicKeyModulus.toByteArray());
String eExponentPublic=Base64.getUrlEncoder().encodeToString(publicKeyExponent.toByteArray());
String nModulusPrivate=Base64.getUrlEncoder().encodeToString(privateKeyModulus.toByteArray());
String eExponentPrivate=Base64.getUrlEncoder().encodeToString(privateKeyExponent.toByteArray());
System.out.println(publicKeyStr);
System.out.println(privateKeyStr);
System.out.println( nModulusPublic);
System.out.println(eExponentPublic);
System.out.println( nModulusPrivate);
System.out.println(eExponentPrivate);
Ответы
Связанный открытый и закрытый ключи имеют одинаковый модуль. Следовательно, различие между nModulusPublicи nModulusPrivateфактически не является необходимым (в отличие от публичной и частной экспоненты).
secondPublicKey()и secondPrivateKey()ожидайте, что модуль ( nModulusPublicили идентичный nModulusPrivate) будет первым аргументом. Вместо этого передается весь ключ ( pubKeyили privKey), что вызывает ошибку. Если вместо этого передается модуль, он работает.
Кстати, модуль и показатель степени закодированы в Base64url и сначала должны быть преобразованы в стандартную кодировку Base64 ( --> +и _-> /). В качестве альтернативы можно использовать декодер Base64url в secondPublicKey()или secondPrivateKey()( Base64.getUrlDecoder()).
Поскольку два открытых или закрытых ключа идентичны (только в разных форматах), для шифрования / дешифрования возможна любая комбинация открытого / закрытого ключей:
String pubKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJXFRUWMDJZ+moC/VbcAXoY5dDxOruwI2B+B+YZRHSRRTKPyd9v0HTqdLeVgufLu/cSxlZAKtZDp9mfgyNdbY9ECAwEAAQ==";
String privKey = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAlcVFRYwMln6agL9VtwBehjl0PE6u7AjYH4H5hlEdJFFMo/J32/QdOp0t5WC58u79xLGVkAq1kOn2Z+DI11tj0QIDAQABAkBC1Bp71OkNAgL47edWWADVja9y9X0R70RYkst/hpQlTrjN4QxzN4k4gCqqdFkno2LfacRO7igMQuVEmYujfkbNAiEA/lU1CyW9J65FXSObsBLxqlNpFw79B2EKUkT6o7b2Ez8CIQCWwJlIyDaoXt7CrvTrPDpok7U93ZKmDPiRjjXDPsGU7wIhAJ6pITIXFO2QNg1ojVNGPiR3bHPKEedsjjfMeF9xYAmZAiAQnfpHg4pC1PJJE2/73g+yJ1X7E8ludE+R+9MBSpGcEQIgBWaVSyTx4e+gSulT93vnMpVsYmiwe53e5t4Uxs+cgSE=";
String nModulusPublic = "AJXFRUWMDJZ-moC_VbcAXoY5dDxOruwI2B-B-YZRHSRRTKPyd9v0HTqdLeVgufLu_cSxlZAKtZDp9mfgyNdbY9E=".replace("-", "+").replace("_","/");
String eExponentPublic = "AQAB".replace("-", "+").replace("_","/");
String nModulusPrivate = "AJXFRUWMDJZ-moC_VbcAXoY5dDxOruwI2B-B-YZRHSRRTKPyd9v0HTqdLeVgufLu_cSxlZAKtZDp9mfgyNdbY9E=".replace("-", "+").replace("_","/");
String eExponentPrivate = "QtQae9TpDQIC-O3nVlgA1Y2vcvV9Ee9EWJLLf4aUJU64zeEMczeJOIAqqnRZJ6Ni32nETu4oDELlRJmLo35GzQ==".replace("-", "+").replace("_","/");
String a, b;
// first/first
a = Encrypt("test", firstPublicKey(pubKey));
b = Decrypt(a, firstPrivateKey(privKey));
System.out.println(b);
// second/second
a = Encrypt("test", secondPublicKey(nModulusPublic, eExponentPublic));
b = Decrypt(a, secondPrivateKey(nModulusPrivate, eExponentPrivate));
System.out.println(b);
// first/second
a = Encrypt("test", firstPublicKey(pubKey));
b = Decrypt(a, secondPrivateKey(nModulusPrivate, eExponentPrivate));
System.out.println(b);
// second/first
a = Encrypt("test", secondPublicKey(nModulusPublic, eExponentPublic));
b = Decrypt(a, firstPrivateKey(privKey));
System.out.println(b);
Обратите внимание, что в опубликованном коде есть опечатка: Encryptиспользуется в сочетании с firstPrivateKey()и Decryptв сочетании с firstPublicKey().