Given a DSAPrivateKey, how to compute corresponding DSAPublicKey? - java

In Java, I have a DSAPrivateKey, which has an X parameter, and also a DSAParams with P, Q and G parameters. I want to compute the corresponding DSAPublicKey. I know I can construct a DSAPublicKeySpec if I know Y, P, Q, and G, and then I can use the KeyFactory.generatePublic(KeySpec) method to turn that into a DSAPublicKey.
The thing I'm not sure about, is how to compute Y given knowledge of X, P, Q and G. I guessed the answer was:
BigInteger y = g.multiply(x).mod(p);
But that produces exception:
Caused by: java.lang.IllegalArgumentException: Y value does not appear to be in correct group
at org.bouncycastle.crypto.asymmetric.KeyUtils.validated(Unknown Source)
at org.bouncycastle.crypto.asymmetric.AsymmetricDSAPublicKey.<init>(Unknown Source)
at org.bouncycastle.jcajce.provider.ProvDSAPublicKey.<init>(Unknown Source)
So obviously that guess isn't right. I also tried:
BigInteger y = g.modPow(x, p);
which gives the same exception.
I'm using BouncyCastle FIPS version 1.0.2, so I'd be happy with an answer that uses BouncyCastle classes, but I'd also be happy with one that doesn't use BouncyC

You were right with the multiplication to get the value y. I found a very handy solution that does work with native Java.
Security warning: the sample program has no exception handling and is for educational purposes only.
Have a nice weekend!
Here is the (short) result of my example program:
Derive DSA PublicKey from PrivateKey
publicKey equals publicKeyDerived: true
full code:
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.spec.DSAPublicKeySpec;
import java.util.Arrays;
public class DSA_RetrievePublicKeyFromPrivateKey {
public static void main(String[] args) throws NoSuchProviderException, NoSuchAlgorithmException {
System.out.println("Derive DSA PublicKey from PrivateKey");
KeyPair keyPair = generateDsaKeyPair(2048);
PublicKey publicKeyOriginal = keyPair.getPublic(); // original for comparison
PublicKey publicKeyDerived = deriveDsaPublicKeyFromPrivatekey(keyPair.getPrivate());
System.out.println("publicKey equals publicKeyDerived: " + Arrays.equals(publicKeyOriginal.getEncoded(), publicKeyDerived.getEncoded()));
}
public static KeyPair generateDsaKeyPair(int keylengthInt)
throws NoSuchAlgorithmException, NoSuchProviderException {
KeyPairGenerator keypairGenerator = KeyPairGenerator.getInstance("DSA", "SUN");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keypairGenerator.initialize(keylengthInt, random);
return keypairGenerator.generateKeyPair();
}
public static PublicKey deriveDsaPublicKeyFromPrivatekey (PrivateKey privateKey) throws NoSuchAlgorithmException {
DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) privateKey;
DSAParams params = dsaPrivateKey.getParams();
BigInteger y = params.getG().modPow(dsaPrivateKey.getX(), params.getP());
DSAPublicKeySpec keySpec = new DSAPublicKeySpec(y, params.getP(), params.getQ(), params.getG());
PublicKey publicKey;
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
try {
publicKey = keyFactory.generatePublic(keySpec);
} catch (Exception e) {
throw new RuntimeException(e);
}
return publicKey;
}
}

Related

Rebuild of a RSA Private Key from modulus & exponent fails

I'm trying to rebuild a RSA keypair from modulus & private/public exponents. The conversion works correct for the public key but fails to private key when comparing the encoded private keys.
When using this rebuild private/public keypair for encryption it works (!) in Java, but when using the rebuild keypair in PHP, the decryption part fails (encryption is working), so it seems to me that the rebuild private key is something different to the "original" private key.
Just for info: using the "original" keypair everything is working fine in PHP.
So my question: how can I retrieve the "original" private key from (BigInteger) modulus & private exponent?
Edit: see my final edit at the end
My sample code shows the equality of public key vs. rebuild one and that the private keys are different:
Rebuilding of a RSA PrivateKey from modulus & exponent
privateKey equals rebuild: false
publicKey equals rebuild: true
code:
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;
public class RebuildRSAPrivateKey {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
System.out.println("Rebuilding of a RSA PrivateKey from modulus & exponent");
// rsa key generation
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
//kpGen.initialize(2048, new SecureRandom());
kpGen.initialize(2048, new SecureRandom());
KeyPair keyPair = kpGen.generateKeyPair();
// private key
PrivateKey privateKey = keyPair.getPrivate();
// get modulus & exponent
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
BigInteger modulus = rsaPrivateKey.getModulus();
BigInteger privateExponent = rsaPrivateKey.getPrivateExponent();
// rebuild the private key
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulus, privateExponent);
PrivateKey privateKeyRebuild = keyFactory.generatePrivate(rsaPrivateKeySpec);
System.out.println("privateKey equals rebuild: " + Arrays.equals(privateKey.getEncoded(), privateKeyRebuild.getEncoded()));
// public key
PublicKey publicKey = keyPair.getPublic();
// get modulus & exponent
RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
BigInteger modulusPub = rsaPublicKey.getModulus();
BigInteger publicExponent = rsaPublicKey.getPublicExponent();
// rebuild the public key
KeyFactory keyFactoryPub = KeyFactory.getInstance("RSA");
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulusPub, publicExponent);
PublicKey publicKeyRebuild = keyFactory.generatePublic(rsaPublicKeySpec);
System.out.println("publicKey equals rebuild: " + Arrays.equals(publicKey.getEncoded(), publicKeyRebuild.getEncoded()));
}
}
Edit: The following programs will show that a RSA private/public keypair derived from encoded keys can get restored and the
encryption and decryption works in Java and PHP. The keys are insecure RSA 512 bit keys and Base64 decoded.
The same keys are then derived from modulus and private/public exponents and the en-/decryption works in Java but not in PHP.
That's why I'd like to get the "original" RSA keys from modulus and exponents, thanks for your kindly help.
Result of Java program:
Rebuilding of a RSA PrivateKey from modulus & exponent v4
privateKey Original Base64: MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEA2wFgcni89ijJ/uijQkzCGF4JiUB1+mEJ48u4Lk0vxB7ym3/FCvOEnN2H7FLUzsGvXRhFriLBiSJlg2tOhV5eiwIDAQABAkEAkDpf4gNRrms+W/mpSshyKsoDTbh9+d5ePP601QlQI79lrsjdy2GLgk4RV1XmwYinM9Sk8G+ssyXTYHdby6A2wQIhAPcRtl6tub6PFiIE1jcuIkib/HzAdRYHZx3ZdzRTYDetAiEA4uv43xpGl5N8yG27Kv0DkRoOlr4Ch6oM24hLVw7ClhcCIFgdRAo+MQlqJH2bdf6WAHoez4x6YwepOjhmD2Jk/eK9AiEAtHgI6J5EEB56+gfS+CBa6tZ3Tcl1x6ElMp8Vk/ooJScCIQDUa3LUkcc58yjJYq8ZNQC/86+HIzd5MldTwg5buR1lpw==
privateKey Rebuild Base64: MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEA2wFgcni89ijJ/uijQkzCGF4JiUB1+mEJ48u4Lk0vxB7ym3/FCvOEnN2H7FLUzsGvXRhFriLBiSJlg2tOhV5eiwIDAQABAkEAkDpf4gNRrms+W/mpSshyKsoDTbh9+d5ePP601QlQI79lrsjdy2GLgk4RV1XmwYinM9Sk8G+ssyXTYHdby6A2wQIhAPcRtl6tub6PFiIE1jcuIkib/HzAdRYHZx3ZdzRTYDetAiEA4uv43xpGl5N8yG27Kv0DkRoOlr4Ch6oM24hLVw7ClhcCIFgdRAo+MQlqJH2bdf6WAHoez4x6YwepOjhmD2Jk/eK9AiEAtHgI6J5EEB56+gfS+CBa6tZ3Tcl1x6ElMp8Vk/ooJScCIQDUa3LUkcc58yjJYq8ZNQC/86+HIzd5MldTwg5buR1lpw==
publicKey Base64: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANsBYHJ4vPYoyf7oo0JMwhheCYlAdfphCePLuC5NL8Qe8pt/xQrzhJzdh+xS1M7Br10YRa4iwYkiZYNrToVeXosCAwEAAQ==
generate private & public key via modulus and private/public exponent
privateKey Modulus Base64: MIGzAgEAMA0GCSqGSIb3DQEBAQUABIGeMIGbAgEAAkEA2wFgcni89ijJ/uijQkzCGF4JiUB1+mEJ48u4Lk0vxB7ym3/FCvOEnN2H7FLUzsGvXRhFriLBiSJlg2tOhV5eiwIBAAJBAJA6X+IDUa5rPlv5qUrIcirKA024ffneXjz+tNUJUCO/Za7I3cthi4JOEVdV5sGIpzPUpPBvrLMl02B3W8ugNsECAQACAQACAQACAQACAQA=
publicKey Modulus Base64: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANsBYHJ4vPYoyf7oo0JMwhheCYlAdfphCePLuC5NL8Qe8pt/xQrzhJzdh+xS1M7Br10YRa4iwYkiZYNrToVeXosCAwEAAQ==
en-/decryption with original keys
ciphertext Original : fvFPRZ5B2GMgv9aXQjyQsxnRHK2wotfXlLV+zGea1E3nsZC6RMn+LQMOe9yvZ8IcaG2F/8wWv2NkNmBX4wuxaw==
decryptedtext Original: this is the message to encrypt
en-/decryption with keys from modulus & exponent
ciphertext Modulus : o0tB4xQIwQRFDSsWj1WgWHexXnJOp9jeBymFPJvy+xZBvfJay2yR0XZEy+0VwaedxdTf9CoyKVvgCbn2HCohSQ==
decryptedtext Modulus : this is the message to encrypt
Result of PHP program:
php version: 7.4.6 openssl version: OpenSSL 1.1.1g 21 Apr 2020
plaintext: this is the message to encrypt
rsa encryption with original keys
priBase64:MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEA2wFgcni89ijJ/uijQkzCGF4JiUB1+mEJ48u4Lk0vxB7ym3/FCvOEnN2H7FLUzsGvXRhFriLBiSJlg2tOhV5eiwIDAQABAkEAkDpf4gNRrms+W/mpSshyKsoDTbh9+d5ePP601QlQI79lrsjdy2GLgk4RV1XmwYinM9Sk8G+ssyXTYHdby6A2wQIhAPcRtl6tub6PFiIE1jcuIkib/HzAdRYHZx3ZdzRTYDetAiEA4uv43xpGl5N8yG27Kv0DkRoOlr4Ch6oM24hLVw7ClhcCIFgdRAo+MQlqJH2bdf6WAHoez4x6YwepOjhmD2Jk/eK9AiEAtHgI6J5EEB56+gfS+CBa6tZ3Tcl1x6ElMp8Vk/ooJScCIQDUa3LUkcc58yjJYq8ZNQC/86+HIzd5MldTwg5buR1lpw==
pubBase64:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANsBYHJ4vPYoyf7oo0JMwhheCYlAdfphCePLuC5NL8Qe8pt/xQrzhJzdh+xS1M7Br10YRa4iwYkiZYNrToVeXosCAwEAAQ==
ciphertext Base64:WmvVwqf2EHQc0yb6L4pVJ0/23pNW4QsBun3SNvYE8p/sEk+1GQSYxYpbY/mLbSGF2Lb1P5g5er+z7dWxHmodNA==
decryptedtext: this is the message to encrypt
rsa encryption with keys created via modulus & exponents
priBase64:MIGzAgEAMA0GCSqGSIb3DQEBAQUABIGeMIGbAgEAAkEA2wFgcni89ijJ/uijQkzCGF4JiUB1+mEJ48u4Lk0vxB7ym3/FCvOEnN2H7FLUzsGvXRhFriLBiSJlg2tOhV5eiwIBAAJBAJA6X+IDUa5rPlv5qUrIcirKA024ffneXjz+tNUJUCO/Za7I3cthi4JOEVdV5sGIpzPUpPBvrLMl02B3W8ugNsECAQACAQACAQACAQACAQA=
pubBase64:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANsBYHJ4vPYoyf7oo0JMwhheCYlAdfphCePLuC5NL8Qe8pt/xQrzhJzdh+xS1M7Br10YRa4iwYkiZYNrToVeXosCAwEAAQ==
ciphertext Base64:kqn8aZpvfpPzr3u2NBX/XmnlFweEvOm+Qu4l2wiUSQCjA0hutQ10mbLaO55oCox7GixvMgb3VtoDBJ8hfW1zbQ==
Cannot Decrypt error:0407109F:rsa routines:RSA_padding_check_PKCS1_type_2:pkcs decoding error
decryptedtext:
decrypt error: error:0909006C:PEM routines:get_name:no start line
Source Java:
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.*;
import java.util.Base64;
public class RebuildRSAPrivateKey4 {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException, IOException {
System.out.println("Rebuilding of a RSA PrivateKey from modulus & exponent v4");
// rsa key generation
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
//kpGen.initialize(2048, new SecureRandom());
kpGen.initialize(512, new SecureRandom()); // don't use 512 bit keys as they are insecure !!
KeyPair keyPair = kpGen.generateKeyPair();
// privateKey Base64: MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEA2wFgcni89ijJ/uijQkzCGF4JiUB1+mEJ48u4Lk0vxB7ym3/FCvOEnN2H7FLUzsGvXRhFriLBiSJlg2tOhV5eiwIDAQABAkEAkDpf4gNRrms+W/mpSshyKsoDTbh9+d5ePP601QlQI79lrsjdy2GLgk4RV1XmwYinM9Sk8G+ssyXTYHdby6A2wQIhAPcRtl6tub6PFiIE1jcuIkib/HzAdRYHZx3ZdzRTYDetAiEA4uv43xpGl5N8yG27Kv0DkRoOlr4Ch6oM24hLVw7ClhcCIFgdRAo+MQlqJH2bdf6WAHoez4x6YwepOjhmD2Jk/eK9AiEAtHgI6J5EEB56+gfS+CBa6tZ3Tcl1x6ElMp8Vk/ooJScCIQDUa3LUkcc58yjJYq8ZNQC/86+HIzd5MldTwg5buR1lpw==
// publicKey Base64: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANsBYHJ4vPYoyf7oo0JMwhheCYlAdfphCePLuC5NL8Qe8pt/xQrzhJzdh+xS1M7Br10YRa4iwYkiZYNrToVeXosCAwEAAQ==
String privateKeyBase64 = "MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEA2wFgcni89ijJ/uijQkzCGF4JiUB1+mEJ48u4Lk0vxB7ym3/FCvOEnN2H7FLUzsGvXRhFriLBiSJlg2tOhV5eiwIDAQABAkEAkDpf4gNRrms+W/mpSshyKsoDTbh9+d5ePP601QlQI79lrsjdy2GLgk4RV1XmwYinM9Sk8G+ssyXTYHdby6A2wQIhAPcRtl6tub6PFiIE1jcuIkib/HzAdRYHZx3ZdzRTYDetAiEA4uv43xpGl5N8yG27Kv0DkRoOlr4Ch6oM24hLVw7ClhcCIFgdRAo+MQlqJH2bdf6WAHoez4x6YwepOjhmD2Jk/eK9AiEAtHgI6J5EEB56+gfS+CBa6tZ3Tcl1x6ElMp8Vk/ooJScCIQDUa3LUkcc58yjJYq8ZNQC/86+HIzd5MldTwg5buR1lpw==";
String publicKeyBase64 = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANsBYHJ4vPYoyf7oo0JMwhheCYlAdfphCePLuC5NL8Qe8pt/xQrzhJzdh+xS1M7Br10YRa4iwYkiZYNrToVeXosCAwEAAQ==";
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyBase64));
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyBase64));
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
System.out.println("privateKey Original Base64: " + privateKeyBase64);
System.out.println("privateKey Rebuild Base64: " + Base64.getEncoder().encodeToString(privateKey.getEncoded()));
System.out.println("publicKey Base64: " + publicKeyBase64);
// get modulus & private exponent via RSAPrivateKey
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
BigInteger modulus = rsaPrivateKey.getModulus();
BigInteger privateExponent = rsaPrivateKey.getPrivateExponent();
// rebuild the private key
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulus, privateExponent);
PrivateKey privateKeyModulusExponent = keyFactory.generatePrivate(rsaPrivateKeySpec);
// public key
RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
BigInteger modulusPub = rsaPublicKey.getModulus();
BigInteger publicExponent = rsaPublicKey.getPublicExponent();
// rebuild the public key
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulusPub, publicExponent);
PublicKey publicKeyModulusExponent = keyFactory.generatePublic(rsaPublicKeySpec);
System.out.println("\ngenerate private & public key via modulus and private/public exponent");
System.out.println("privateKey Modulus Base64: " + Base64.getEncoder().encodeToString(privateKeyModulusExponent.getEncoded()));
System.out.println("publicKey Modulus Base64: " + Base64.getEncoder().encodeToString(publicKeyModulusExponent.getEncoded()));
System.out.println("\nen-/decryption with original keys");
String plaintext = "this is the message to encrypt";
String ciphertextOriginal = encrypt(publicKey, plaintext);
String decryptedtextOriginal = decrypt(privateKey, ciphertextOriginal);
System.out.println("ciphertext Original : " + ciphertextOriginal);
System.out.println("decryptedtext Original: " + decryptedtextOriginal);
System.out.println("\nen-/decryption with keys from modulus & exponent");
String ciphertextModulus = encrypt(publicKeyModulusExponent, plaintext);
String decryptedtextModulus = decrypt(privateKeyModulusExponent, ciphertextOriginal);
System.out.println("ciphertext Modulus : " + ciphertextModulus);
System.out.println("decryptedtext Modulus : " + decryptedtextModulus);
}
private static String encrypt(PublicKey publicKey, String plaintext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException, BadPaddingException, IllegalBlockSizeException {
String ciphertext = "";
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] ciphertextByte = cipher.doFinal(plaintext.getBytes("UTF8"));
ciphertext = Base64.getEncoder().encodeToString(ciphertextByte).replaceAll("\\r|\\n", "");
return ciphertext;
}
private static String decrypt(PrivateKey privateKey, String ciphertext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] ciphertextByte = Base64.getDecoder().decode(ciphertext);
byte[] decryptedtextByte = cipher.doFinal(ciphertextByte);
return new String(decryptedtextByte);
}
private static String bytesToHex(byte[] bytes) {
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
}
Source PHP:
<?php
function encrypt($publicKeyBase64, $plaintext){
$pub = base64_decode($publicKeyBase64);
// public key conversion der to pem
$pubPem = chunk_split(base64_encode($pub), 64, "\n");
$pubPem = "-----BEGIN PUBLIC KEY-----\n" . $pubPem . "-----END PUBLIC KEY-----\n";
$ublicKey = "";
$publicKey = openssl_get_publickey($pubPem);
if (!$publicKey) {
echo "Cannot get public key" . "<br>";
}
$ciphertext = "";
openssl_public_encrypt($plaintext, $ciphertext, $publicKey);
if (!empty($ciphertext)) {
openssl_free_key($publicKey);
//echo "Encryption OK!" . "<br>";
} else {
echo "Cannot Encrypt" . "<br>";
}
$ciphertextBase64 = base64_encode($ciphertext);
return $ciphertextBase64;
}
function decrypt($privateKeyBase64, $ciphertext){
$pri = base64_decode($privateKeyBase64);
// private key conversion der to pem
$priPem = chunk_split(base64_encode($pri), 64, "\n");
$priPem = "-----BEGIN PRIVATE KEY-----\n" . $priPem . "-----END PRIVATE KEY-----\n";
$privateKey = openssl_get_privatekey($priPem);
$Crypted = openssl_private_decrypt($ciphertext, $decryptedtext, $privateKey);
if (!$Crypted) {
echo 'Cannot Decrypt ' . openssl_error_string() . '<br>';
} else {
openssl_free_key($privateKey);
//echo "decryptedtext: " . $decryptedtext . "<br>";
}
return $decryptedtext;
}
echo 'php version: ' . PHP_VERSION . ' openssl version: ' . OPENSSL_VERSION_TEXT . '<br>';
$plaintext = "this is the message to encrypt";
echo "plaintext: " . $plaintext . "<br>";
// RSA 512 keys from Java GenerateKeysSo.java
echo 'rsa encryption with original keys' . '<br>';
$priBase64 = "MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEA2wFgcni89ijJ/uijQkzCGF4JiUB1+mEJ48u4Lk0vxB7ym3/FCvOEnN2H7FLUzsGvXRhFriLBiSJlg2tOhV5eiwIDAQABAkEAkDpf4gNRrms+W/mpSshyKsoDTbh9+d5ePP601QlQI79lrsjdy2GLgk4RV1XmwYinM9Sk8G+ssyXTYHdby6A2wQIhAPcRtl6tub6PFiIE1jcuIkib/HzAdRYHZx3ZdzRTYDetAiEA4uv43xpGl5N8yG27Kv0DkRoOlr4Ch6oM24hLVw7ClhcCIFgdRAo+MQlqJH2bdf6WAHoez4x6YwepOjhmD2Jk/eK9AiEAtHgI6J5EEB56+gfS+CBa6tZ3Tcl1x6ElMp8Vk/ooJScCIQDUa3LUkcc58yjJYq8ZNQC/86+HIzd5MldTwg5buR1lpw==";
$pubBase64 = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANsBYHJ4vPYoyf7oo0JMwhheCYlAdfphCePLuC5NL8Qe8pt/xQrzhJzdh+xS1M7Br10YRa4iwYkiZYNrToVeXosCAwEAAQ==";
echo 'priBase64:' . $priBase64 . '<br>';
echo 'pubBase64:' . $pubBase64 . '<br>';
$ciphertextBase64 = encrypt($pubBase64, $plaintext);
echo 'ciphertext Base64:' . $ciphertextBase64 . '<br>';
$ciphertext = base64_decode($ciphertextBase64);
$decryptedtext = decrypt($priBase64, $ciphertext);
echo "decryptedtext: " . $decryptedtext . "<br><br>";
// keys created via modulus & exponent
$priBase64 = "MIGzAgEAMA0GCSqGSIb3DQEBAQUABIGeMIGbAgEAAkEA2wFgcni89ijJ/uijQkzCGF4JiUB1+mEJ48u4Lk0vxB7ym3/FCvOEnN2H7FLUzsGvXRhFriLBiSJlg2tOhV5eiwIBAAJBAJA6X+IDUa5rPlv5qUrIcirKA024ffneXjz+tNUJUCO/Za7I3cthi4JOEVdV5sGIpzPUpPBvrLMl02B3W8ugNsECAQACAQACAQACAQACAQA=";
$pubBase64 = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANsBYHJ4vPYoyf7oo0JMwhheCYlAdfphCePLuC5NL8Qe8pt/xQrzhJzdh+xS1M7Br10YRa4iwYkiZYNrToVeXosCAwEAAQ==";
echo 'rsa encryption with keys created via modulus & exponents' . '<br>';
echo 'priBase64:' . $priBase64 . '<br>';
echo 'pubBase64:' . $pubBase64 . '<br>';
$ciphertextBase64 = encrypt($pubBase64, $plaintext);
echo 'ciphertext Base64:' . $ciphertextBase64 . '<br>';
$ciphertext = base64_decode($ciphertextBase64);
$decryptedtext = decrypt($priBase64, $ciphertext);
echo "decryptedtext: " . $decryptedtext . "<br><br>";
echo 'decrypt error: error:0909006C:PEM routines:get_name:no start line' . '<br>';
?>
Final Edit solution & conclusion
If we want to use a RSA private-public keypair for encryption (and signing as well ?) in other systems than Java it is of importance that the private key is saved immeditaly. If we are trying to rebuild the private key from the encoded form (via PKCS8EncodedKeySpec) some data are definitely missing. Those rebuild private keys will fail to work (here in PHP/openssl).
If we need to rebuild a private key from the encoded-form (byte[]) the keys need to get enhanced via a method called "createCrtKey" - this method was written by President James K. Polk and all credits go to him. As links sometimes date out I marked my own answer below as accepted one because the createCrtKey-method is documented there.
Thanks to #President James K. Polk, #Topaco and #michalk for guiding me into the right direction.
The minimal information needed to perform the RSA decrypt operation is the modulus n and the decrypt exponent d. There's an optimization that can be applied to RSA decryption involving the Chinese Remainder Theorem whereby exponentiations are done mod the RSA primes separately and then combined to produce a final value, and thus there are some extra fields fields for this purpose in the RSA Private Key syntax and the Java RSAPrivateCrtKey interface modeled after it.
Now the question being raised here is: When are two RSAPrivateCrtKey instances equal? I would argue that they are equal when they function identically in the RSA algorithm. You are asking for a more narrow definition, namely they are equal when their encoded forms are equal. The problem with this definition is that it is too implementation-specific. Currently, when the "Sun" provider generates a key pair it always orders the primes p and q such that p > q. But I like it the other way, where p < q. The RSAPrivateCrtKey interface does not care either way as it does no checking. The Javadocs for the interface do not specify an order. You can change my code to produce what should be the same encoded form as the current "Sun" implementation simply by reversing the comparison in p.compareTo(q) > 0. However, the default implementation can change to match my preference in the future, and it will if my plan to take over the world succeeds. The Javadocs are the specification, and the implementation may change as long as it complies with the Javadocs.
Below I have provided an implementation of an equality function in which I have tried to incorporate the widest possible notion of equality consistent with the specification. That is, any two RSAPrivateCRTKey instances for which keyEquals returns true should produce identical results when used in the RSA algorithm, and if false is returned then there should be at least one value for which they produce different results.
public static boolean keyEquals(RSAPrivateCrtKey k1, RSAPrivateCrtKey k2) {
final BigInteger ZERO = BigInteger.ZERO;
boolean result = true;
result = result && isConsistent(k1) && isConsistent(k2);
result = result && k1.getModulus().equals(k2.getModulus());
BigInteger lambda = computeCarmichaelLambda(k1.getPrimeP(), k1.getPrimeQ());
result = result && k1.getPublicExponent().subtract(k2.getPublicExponent()).mod(lambda).equals(ZERO);
result = result && k1.getPrivateExponent().subtract(k2.getPrivateExponent()).mod(lambda).equals(ZERO);
return result;
}
private static boolean isConsistent(RSAPrivateCrtKey k1) {
final BigInteger ZERO = BigInteger.ZERO;
final BigInteger ONE = BigInteger.ONE;
BigInteger n = k1.getModulus();
BigInteger p = k1.getPrimeP();
BigInteger q = k1.getPrimeQ();
BigInteger e = k1.getPublicExponent();
BigInteger d = k1.getPrivateExponent();
boolean result = true;
result = p.multiply(q).equals(n);
BigInteger lambda = computeCarmichaelLambda(p, q);
result = result && e.multiply(d).mod(lambda).equals(ONE);
result = result && d.subtract(key.getPrimeExponentP()).mod(p.subtract(ONE)).equals(ZERO);
result = result && d.subtract(key.getPrimeExponentQ()).mod(q.subtract(ONE)).equals(ZERO);
result = result && q.multiply(k1.getCrtCoefficient()).mod(p).equals(ONE);
return result;
}
private static BigInteger computeCarmichaelLambda(BigInteger p, BigInteger q) {
return lcm(p.subtract(BigInteger.ONE), q.subtract(BigInteger.ONE));
}
private static BigInteger lcm(BigInteger x, BigInteger y) {
return x.multiply(y).divide(x.gcd(y));
}
This is the modified version of my program that has the additional code from #President James K. Polk (see link of Topaco above). Even if the rebuild CRT-private key is now longer than the rebuild Private Key it does not match the original (encoded)
private key. As I'm using the encoded private and public keys for a PHP RSA encryption/decryption there is the funny fact that the original keys run successfully but the rebuild ones not...
This version uses a 512 bit keylength that is insecure is for demonstration only (to keep the keys shorter).
result:
Rebuilding of a RSA PrivateKey from modulus & exponent
privateKey equals rebuild: false
publicKey equals rebuild: true
privateKey original encoded: 30820154020100300d06092a864886f70d01010105000482013e3082013a020100024100a45477b9f00f51c8e1d5cb961a485c74ee123aa6da5c5bfd43f62acee9b684a8f140bb7a68996a77d04bdaabc5f259cb38a7bef909f4d85c6a597519a09aec9b0203010001024066ea4fa12f6b28b93a567f0e1e9fbae7b041d261b4d7aaf4ce9f58e8050ebdbd5e2a6261f06de2d72c4fdc6a62465f9cad9e8f5860bb2f8395cd903a214fb441022100e3b260dcced139557591b609470d8f0e518351a97bdbf26a59a41140a68778e9022100b8c1ab98f7b7280bd4b53fa3ed09c11d12aec9873d8a4a05e43152bc0d3346e302201d801ff29bcd19bb8bc6fc29c98de529fabfa3d5ec993b9831d302f5385e36f90220009e0d0fbecc2ae3173bdfd1916a35edfdf0fd95691c3c3116d91f58a786a357022100a810110da3d9d4de34e64029a3535368bb52e7b81055239cb4443d5172aea8e5
privateKey rebuild encoded: 3081b2020100300d06092a864886f70d010101050004819d30819a020100024100a45477b9f00f51c8e1d5cb961a485c74ee123aa6da5c5bfd43f62acee9b684a8f140bb7a68996a77d04bdaabc5f259cb38a7bef909f4d85c6a597519a09aec9b020100024066ea4fa12f6b28b93a567f0e1e9fbae7b041d261b4d7aaf4ce9f58e8050ebdbd5e2a6261f06de2d72c4fdc6a62465f9cad9e8f5860bb2f8395cd903a214fb441020100020100020100020100020100
privateKey rebuild CRT encoded: 30820153020100300d06092a864886f70d01010105000482013d30820139020100024100a45477b9f00f51c8e1d5cb961a485c74ee123aa6da5c5bfd43f62acee9b684a8f140bb7a68996a77d04bdaabc5f259cb38a7bef909f4d85c6a597519a09aec9b0203010001024066ea4fa12f6b28b93a567f0e1e9fbae7b041d261b4d7aaf4ce9f58e8050ebdbd5e2a6261f06de2d72c4fdc6a62465f9cad9e8f5860bb2f8395cd903a214fb441022100b8c1ab98f7b7280bd4b53fa3ed09c11d12aec9873d8a4a05e43152bc0d3346e3022100e3b260dcced139557591b609470d8f0e518351a97bdbf26a59a41140a68778e90220009e0d0fbecc2ae3173bdfd1916a35edfdf0fd95691c3c3116d91f58a786a35702201d801ff29bcd19bb8bc6fc29c98de529fabfa3d5ec993b9831d302f5385e36f9022030634f5490e1bb4b56a68715d3c80a92c6e8f7c9f3e79f125a9969e6fc095705
code:
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;
public class RebuildRSAPrivateKey2 {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
System.out.println("Rebuilding of a RSA PrivateKey from modulus & exponent");
// rsa key generation
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
//kpGen.initialize(2048, new SecureRandom());
kpGen.initialize(512, new SecureRandom()); // don't use 512 bit keys as they are insecure !!
KeyPair keyPair = kpGen.generateKeyPair();
// private key
PrivateKey privateKey = keyPair.getPrivate();
// get modulus & exponent
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
BigInteger modulus = rsaPrivateKey.getModulus();
BigInteger privateExponent = rsaPrivateKey.getPrivateExponent();
// rebuild the private key
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulus, privateExponent);
PrivateKey privateKeyRebuild = keyFactory.generatePrivate(rsaPrivateKeySpec);
System.out.println("privateKey equals rebuild: " + Arrays.equals(privateKey.getEncoded(), privateKeyRebuild.getEncoded()));
// public key
PublicKey publicKey = keyPair.getPublic();
// get modulus & exponent
RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
BigInteger modulusPub = rsaPublicKey.getModulus();
BigInteger publicExponent = rsaPublicKey.getPublicExponent();
// rebuild the public key
KeyFactory keyFactoryPub = KeyFactory.getInstance("RSA");
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulusPub, publicExponent);
PublicKey publicKeyRebuild = keyFactory.generatePublic(rsaPublicKeySpec);
System.out.println("publicKey equals rebuild: " + Arrays.equals(publicKey.getEncoded(), publicKeyRebuild.getEncoded()));
System.out.println("\nprivateKey original encoded: " + bytesToHex(privateKey.getEncoded()));
System.out.println("privateKey rebuild encoded: " + bytesToHex(privateKeyRebuild.getEncoded()));
RSAPrivateKey rsaPrivateKeyRebuild = (RSAPrivateKey) privateKeyRebuild;
RSAPublicKey rsaPublicKeyRebuild = (RSAPublicKey) publicKeyRebuild;
RSAPrivateCrtKey rsaPrivateCrtKey = createCrtKey(rsaPublicKeyRebuild, rsaPrivateKeyRebuild);
System.out.println("privateKey rebuild CRT encoded: " + bytesToHex(rsaPrivateCrtKey.getEncoded()));
}
/**
* https://stackoverflow.com/questions/43136036/how-to-get-a-rsaprivatecrtkey-from-a-rsaprivatekey
* answered Mar 31 '17 at 18:16 President James K. Polk
* Find a factor of n by following the algorithm outlined in Handbook of Applied Cryptography, section
* 8.2.2(i). See http://cacr.uwaterloo.ca/hac/about/chap8.pdf.
*
*/
private static BigInteger findFactor(BigInteger e, BigInteger d, BigInteger n) {
BigInteger edMinus1 = e.multiply(d).subtract(BigInteger.ONE);
int s = edMinus1.getLowestSetBit();
BigInteger t = edMinus1.shiftRight(s);
for (int aInt = 2; true; aInt++) {
BigInteger aPow = BigInteger.valueOf(aInt).modPow(t, n);
for (int i = 1; i <= s; i++) {
if (aPow.equals(BigInteger.ONE)) {
break;
}
if (aPow.equals(n.subtract(BigInteger.ONE))) {
break;
}
BigInteger aPowSquared = aPow.multiply(aPow).mod(n);
if (aPowSquared.equals(BigInteger.ONE)) {
return aPow.subtract(BigInteger.ONE).gcd(n);
}
aPow = aPowSquared;
}
}
}
public static RSAPrivateCrtKey createCrtKey(RSAPublicKey rsaPub, RSAPrivateKey rsaPriv) throws NoSuchAlgorithmException, InvalidKeySpecException {
BigInteger e = rsaPub.getPublicExponent();
BigInteger d = rsaPriv.getPrivateExponent();
BigInteger n = rsaPub.getModulus();
BigInteger p = findFactor(e, d, n);
BigInteger q = n.divide(p);
if (p.compareTo(q) > 0) {
BigInteger t = p;
p = q;
q = t;
}
BigInteger exp1 = d.mod(p.subtract(BigInteger.ONE));
BigInteger exp2 = d.mod(q.subtract(BigInteger.ONE));
BigInteger coeff = q.modInverse(p);
RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(n, e, d, p, q, exp1, exp2, coeff);
KeyFactory kf = KeyFactory.getInstance("RSA");
return (RSAPrivateCrtKey) kf.generatePrivate(keySpec);
}
private static String bytesToHex(byte[] bytes) {
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
}

divide rsa private key in two halves

i would like to divide the rsa private key into two halves and store them in two different places, how can I do it?
public GenerateKeys(int keylength) throws NoSuchAlgorithmException, NoSuchProviderException {
keylength=512;
this.keyGen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
this.keyGen.initialize(keylength, random);
}
Here is a example, which will split your private key in to two parts, D1 and D2. Similar to the discussion presented here
import java.security.KeyPair;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class OnetimePad{
public static byte[] xor(byte[] key, byte[] rand){
if(key.length != rand.length){
return null;
}
byte[] ret = new byte[key.length];
for(int i =0; i < key.length; i++){
ret[i] = (byte)((key[i] ^ rand[i]) );
}
return ret;
}
public static void main(String []args) throws Exception{
SecureRandom random = new SecureRandom();
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair keypair = keyGen.genKeyPair();
PrivateKey privateKey = keypair.getPrivate();
byte[] privateKeyBytes = privateKey.getEncoded();
//Private Key Part 1
byte[] D1 = new byte[privateKeyBytes.length];
random.nextBytes(D1);
//Private Key Part 2
byte[] D2 = xor(privateKeyBytes, D1);
//now D1 and D2 are split parts of private keys..
//Let's verify if we could reproduce them back
byte[] privateKeyByesTmp = xor(D2, D1);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyByesTmp);
PrivateKey privateKey2 = keyFactory.generatePrivate(privateKeySpec);
boolean same = privateKey.equals(privateKey2);
if(same){
System.out.println("Key loaded successfully");
}else{
System.out.println("Ooops");
}
}
}
Note:
Please check following documentation of SecureRandom on random seed. Specially the section highlighted
Many SecureRandom implementations are in the form of a pseudo-random number generator (PRNG), which means they use a deterministic algorithm to produce a pseudo-random sequence from a true random seed. Other implementations may produce true random numbers, and yet others may use a combination of both techniques.

Java RSA Decryption

I'm having trouble decrypting some text
public class mainClass {
private static Cipher cipher;
private static KeyPairGenerator keyGen;
private static KeyPair pair;
private static PrivateKey privateKey;
private static PublicKey publicKey;
public static void createKeys() {
pair = keyGen.generateKeyPair();
privateKey = pair.getPrivate();
publicKey = pair.getPublic();
}
public static String encryptText(String msg)
throws NoSuchAlgorithmException, NoSuchPaddingException,
UnsupportedEncodingException, IllegalBlockSizeException,
BadPaddingException, InvalidKeyException {
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return Base64.getEncoder().encodeToString((cipher.doFinal(msg.getBytes("UTF-8"))));
}
public static String decryptText(String msg)
throws InvalidKeyException, UnsupportedEncodingException,
IllegalBlockSizeException, BadPaddingException {
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return new String(cipher.doFinal(Base64.getDecoder().decode(msg)), "UTF-8");
}
public static void main(String args[]) throws Exception {
int keylength = 1024;
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(keylength, random);
cipher = Cipher.getInstance("RSA");
createKeys();
FileInputStream f = new FileInputStream("C:\\Users\\caleb.baker\\Downloads\\test100k.db");
byte[] b = new byte[f.available()];
int offset = 0;
String asf = "";
f.read(b);
String test = new String(b);
for (int x = 0; x < b.length; x += 117) {
try {
asf += encryptText(test.substring(x, x + 117));
} catch (StringIndexOutOfBoundsException e) {
asf += encryptText(test.substring(x));
}
}
String t = asf;
asf = "";
for (int x = 0; x < t.length(); x += 117) {
System.out.println("run");
try {
asf += decryptText(test.substring(x, x + 117));
} catch (StringIndexOutOfBoundsException e) {
asf += decryptText(test.substring(x));
}
}
}
}
The error i get is
Exception in thread "main"
java.lang.IllegalArgumentException: Last unit does not have enough valid bits
at java.util.Base64$Decoder.decode0(Unknown Source)
at java.util.Base64$Decoder.decode(Unknown Source)
at java.util.Base64$Decoder.decode(Unknown Source)
at mainClass.decryptText(mainClass.java:60)
at mainClass.main(mainClass.java:162)
I'm pretty new to encryption. the symmetric AES worked great, and I know its faster but for my own curiosity I want to time RSA. Another error I will get is a bad padding exception. I have been working on it some but I think that may be laying around in my code somewhere waiting to get me.
Also the Encryption works fine. I did not check to see if it was correct but I did print out the length to make sure the string was long enough. the loop for decryption never makes it past the first loop
there are multiple issues with your program
as already commented - wrong keys are used (private key is to be used to decrypt, public key is to be used to encrypt)
RSA is to be used to encrypt only limited amount of data, not text of any length. It can be used that way, but under some circumstances it may be not secure
Last unit does not have enough valid bits means the base64 encoded value is not valid. Decoding base64 means transforming 4 bytes of 6 bit encoding to 3 bytes of 8 bits. so the length of the decoded part must be multiplier of 4 (which 1177 is not) the same goes with the encryption loop, just joining multiple base64 string doesn't necessary result in valid b64 value.
I did not get purpose of the loops in the program., imho it is overcomplicated, you ought to keep it simple. what were you trying to achieve?
Another error I will get is a bad padding exception. RSA (default cipher RSA/ECB/pkcs1padding) adds padding to the value to be encrypted. So you cannot just take any value and decrypt it otherwise the padding won't be valid (which happens in the loops with some substring)
Some time ago I wrote a blog about encryption in Java you may get some inspiration from

Reconstructing private and public keys with Bouncy Castle?

If I get the actual key with getEncoded from a public or a private key in Bouncy Castle in Java (actual class seems to be BCECPublicKey and BCECPrivateKey). Is it possible to reconstruct the key objects to use them in code?
I found out here in Stack Overflow how to serialize the whole object to binary (and then to disk) and then back to binary and to an object of the appropriate class, but I believe that serialization contains implementation details and if I try to use those keys with anything else than Bouncy Castle, it'll fail. I'm not trying to do that now, but I want to future-proof my program.
This is how I'm creating the keys:
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");
keyPairGenerator.initialize(new ECGenParameterSpec("secp521r1"), new SecureRandom());
java.security.KeyPair keyPair = keyPairGenerator.generateKeyPair();
privateKey = keyPair.getPrivate();
publicKey = keyPair.getPublic();
The KeyFactory is used to convert between encoded keys and the Java classes that represent them. However, the KeyFactory instance doesn't convert directly between a byte array and a Key class. Instead, you must already know what format the encoding uses, and then create a KeySpec object using the byte array in the constructor. The format can be determined by called the getFormat() method on the key. Here is an example illustrating some of these points.
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class Main {
public static void main(String[] args) throws Exception{
Security.addProvider(new BouncyCastleProvider());
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");
keyPairGenerator.initialize(new ECGenParameterSpec("secp521r1"), new SecureRandom());
java.security.KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
System.out.println(privateKey.getFormat());
PublicKey publicKey = keyPair.getPublic();
System.out.println(publicKey.getFormat());
// A KeyFactory is used to convert encoded keys to their actual Java classes
KeyFactory ecKeyFac = KeyFactory.getInstance("EC", "BC");
// Now do a round-trip for a private key,
byte [] encodedPriv = privateKey.getEncoded();
// now take the encoded value and recreate the private key
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(encodedPriv);
PrivateKey privateKey2 = ecKeyFac.generatePrivate(pkcs8EncodedKeySpec);
// And a round trip for the public key as well.
byte [] encodedPub = publicKey.getEncoded();
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(encodedPub);
PublicKey publicKey2 = ecKeyFac.generatePublic(x509EncodedKeySpec);
System.out.println(publicKey2);
}
}

Android XML RSA, ERROR: java.security.InvalidKeyException: unknown key type passed to RSA

i got problem Encrypting a string using RSA.
my RSA is in XML format, it looks like that:
<RSAKeyValue><Modulus>lT8ykfyV0R8o3mJZZezLKTKJpYB90Pzvp0moLzh9CTGfgsxLKYiAl+YGaoRfQ7hVQos5UlLIONHWKPNco9kKcmL6EBJvFc8wqBnhX0p4ML2WSv1yDIRsm9XXra82WHIa3+fxK8bNUJHrucxmpr9pDRPdZGZkz+Q9s94FcOyFKbs=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
and i'm trying to encrypt a string using this class:
import java.io.BufferedReader;
import java.io.StringReader;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.Security;
import javax.crypto.Cipher;
import org.bouncycastle.openssl.PEMReader;
import android.util.Base64;
import android.util.Log;
public class RsaEncryption {
private String publicKey;
public RsaEncryption(String publicKey)
{
this.publicKey = publicKey;
}
/*
* Function to encrypt the data.
*
*/
public String encrypt( String data ) throws Exception
{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
byte[] keyBytes = Base64.decode( this.publicKey, 0 );
PublicKey publickey = strToPublicKey(new String(keyBytes));
cipher.init( Cipher.ENCRYPT_MODE , publickey );
// Base 64 encode the encrypted data
byte[] encryptedBytes = Base64.encode( cipher.doFinal(data.getBytes()), 0 );
return new String(encryptedBytes);
}
public static PublicKey strToPublicKey(String s)
{
PublicKey pbKey = null;
try {
BufferedReader br = new BufferedReader( new StringReader(s) );
PEMReader pr = new PEMReader(br);
Object obj = pr.readObject();
if( obj instanceof PublicKey )
{
pbKey = (PublicKey) pr.readObject();
}
else if( obj instanceof KeyPair )
{
KeyPair kp = (KeyPair) pr.readObject();
pbKey = kp.getPublic();
}
pr.close();
}
catch( Exception e )
{
Log.d("CIPHER", e.getMessage() );
}
return pbKey;
}
}
as you can see i'm using bouncycastle's jar
the error that i get is:
java.security.InvalidKeyException: unknown key type passed to RSA
I'm not sure about this part
Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
maybe this is the problem?
if it is, what need to be there instead?
i did hours of research and still didn't find a solution...
Thanks in advance :)
Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
maybe this is the problem?
No it's not.
OAEPWith<digest>And<mgf>Padding
Means Optimal Asymmetric Encryption Padding scheme defined in PKCS1, where <digest> should be replaced by the message digest algorithm and <mgf> by the mask generation function. Examples: OAEPWithMD5AndMGF1Padding and OAEPWithSHA-512AndMGF1Padding.
Reference Standard Names and RFC 4055.
The problem is in your Public Key generation. As your key is in XML, and Base64 encoded:
First you need to separate modulus and exponent.
Then Base64 decode both modulus and exponent.
After decoding you will get the byte array of modulus and exponent, so you can easily prepare public key object like the following procedure:
BigInteger modBigInteger = new BigInteger(1, modulus);//modulus must be byte array
BigInteger exBigInteger = new BigInteger(1, exponent);//exp must be byte array
RSAPublicKeySpec spec = new RSAPublicKeySpec(modBigInteger, exBigInteger);
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey publicKey = factory.generatePublic(spec);
XML is not PEM.
You need to extract the modulus and the public exponent from the XML and then generate a key using an "RSA" KeyFactory instance and a RSAPublicKeySpec.

Categories