I have been reading some RSA literature and stack overflow questions, but I didn't get a definitive answer.
Given a RSA private key modulus and private exponent only, which is all I have (and also enough for all crypto related operations), can I get the associated public key modulus and public exponent?
Also, can I get the encoded form of the private key with only those two parameters? I've tried the following in java (java is not an actual requeriment), however the OpenSSL engine that backs it fails with error:04000090:RSA routines:OPENSSL_internal:VALUE_MISSING
@NonNull
public static byte[] getEncodedRsaPrivateKey(@NonNull BigInteger nModulus, @NonNull BigInteger nPrivateExponent) throws NoSuchAlgorithmException, InvalidKeySpecException {
RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(nModulus, nPrivateExponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
return privateKey.getEncoded();
}
I guess the answer is no for both questions, but I'm not sure.
Generally the RSA private key contains the following data:
n - semiprime modulus
d - private exponent
p & q - prime factors of n
e - public exponent
At a minimum, the private key must contain:
n and d.So to answer your questions:
can I get the associated public key modulus?
Yep, you already have it. It's the same n used by the private key.
can I get the public exponent?
Not easily without knowing p and q, though you can guess at it, it's nearly always a small prime, most commonly either 3 or 65537.
Try both and check if ciphertext is valid.
As instructed by @Woodstock, I searched for the public exponent and succeeded:
int nPublicExponent;
boolean bFound = false;
for (nPublicExponent = 3; nPublicExponent <= 65537; nPublicExponent++) {
publicKeySpec = new RSAPublicKeySpec(privateKey.getModulus(), new BigInteger(String.valueOf(nPublicExponent)));
publicKey = rsaKeyFactory.generatePublic(publicKeySpec);
if (publicKey == null) {
continue;
}
byte[] encryptMessage = testEncrypt("hello", publicKey);
if (encryptMessage == null) {
continue;
}
String sMessage = testDecrypt(encryptMessage, privateKey);
if (TextUtils.isEmpty(sMessage)) {
continue;
}
if (TextUtils.equals(sMessage, "hello")) {
bFound = true;
break;
}
}
if (!bFound) {
Utils.DebugLog("Public exponent not found");
} else {
Utils.DebugLog("Public exponent found: " + nPublicExponent);
}
@Nullable
public static byte[] testEncrypt(String sMessage, PublicKey publicKey) {
try {
Cipher encrypt = Cipher.getInstance("RSA/ECB/PKCS1Padding");
encrypt.init(Cipher.ENCRYPT_MODE, publicKey);
return encrypt.doFinal(sMessage.getBytes());
} catch (Exception ex) {
return null;
}
}
@Nullable
public static String testDecrypt(byte[] encryptedMessage, Key privateKey) {
try {
Cipher decrypt = Cipher.getInstance("RSA/ECB/PKCS1Padding");
decrypt.init(Cipher.DECRYPT_MODE, privateKey);
return new String(decrypt.doFinal(encryptedMessage));
} catch (Exception ex) {
return null;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With