Unable to get PrivateKey from PKCS8 - java

Unable to get PrivateKey from self generated PKCS8.
I've generated private key:
KeyPair pair = getKeyPair();
StringWriter privateWriter = new StringWriter();
try (JcaPEMWriter w = new JcaPEMWriter(privateWriter)) {
w.writeObject(new JcaPKCS8Generator(pair.getPrivate(), null));
} catch (IOException e) {
throw new RuntimeException(e);
}
And now I'm trying to get Private Key from String.
private PrivateKey getPrivateKeyFromString(String key) {
key = """
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCoY5d/IeuUhznJ
HIxqSibQks5Hdm/2nd5HWvD/Jcdcd6wfjHuoUZyFarhm5sWR6aBj1ZAcj7o0hXPS
gRA64ka/eA09YcLe0FunKyUUwXihize3VbDDOrTqRgLdPdnbtcwFIYDok40IIUlK
...
x08Iqpel5FehCpIDAh/jqPNBfKLWV5TpRxvBDdrBAoGBALyv5VCiJjIUOgAsJ5cb
SwJLPGrlp7xSoe69TQ7Uc+GcvMwokP1hJCnaicKy/AyvQeBS5CQLu0nOfr0vy1mF
jAwpBvorgZ3HBlUYzIDyJKeep7Lj5nKHs5FicAOpTJCaKZAeruMW91Qh6KaMZwYb
hMg1M4O1HSDOsdDBg6wuoLqv
-----END PRIVATE KEY-----
""";
byte[] keyBytes = key.getBytes();
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = null;
try {
keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(spec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new RuntimeException(e);
}
}
When running getPrivateKeyFromString gGetting an exception:
java.security.InvalidKeyException: invalid key format

Topaco answer helped a lot. This code works now.
private PrivateKey getPrivateKeyFromString(String key) {
key = """
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCoY5d/IeuUhznJ
HIxqSibQks5Hdm/2nd5HWvD/Jcdcd6wfjHuoUZyFarhm5sWR6aBj1ZAcj7o0hXPS
...
jAwpBvorgZ3HBlUYzIDyJKeep7Lj5nKHs5FicAOpTJCaKZAeruMW91Qh6KaMZwYb
hMg1M4O1HSDOsdDBg6wuoLqv
-----END PRIVATE KEY-----
""";
key = key.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\n", "");
byte[] keyBytes = Base64.getDecoder().decode(key);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory;
try {
keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(spec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new RuntimeException(e);
}
}

Related

Reconstruct private key

I am generating Asymmetric public key and private using the code below.
public static KeyPair generateRSAKkeyPair()
throws Exception {
SecureRandom secureRandom = new SecureRandom();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(
2048, secureRandom);
return keyPairGenerator
.generateKeyPair();
}
public static byte[] do_RSAEncryption(
String plainText,
PublicKey publicKey)
throws Exception {
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(
Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(
plainText.getBytes());
}
public static String do_RSADecryption(
byte[] cipherText,
PrivateKey privateKey)
throws Exception {
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.DECRYPT_MODE,
privateKey);
byte[] result = cipher.doFinal(cipherText);
return new String(result);
}
public static PublicKey getKey(String key) {
try {
byte[] byteKey = Base64.getDecoder().decode(key.getBytes());
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(X509publicKey);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static PrivateKey getPrivateKey(String key) {
try {
byte[] byteKey = Base64.getDecoder().decode(key.getBytes());
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(X509publicKey);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
This works as expected.
String plainText = "This is the PlainText. I want to Encrypt using RSA.";
byte[] cipherText = do_RSAEncryption(plainText, keypair.getPublic());
String decryptedText = do_RSADecryption(cipherText, keypair.getPrivate());
Now, I am storing the generated the generated public key and private key in a string and trying to encrypt and decrypt and it is failing.
String base64EncodedEncryptionKey = DatatypeConverter.printBase64Binary(keypair.getPublic().getEncoded()));
String base64EccodedDecryptionKey = DatatypeConverter.printBase64Binary(keypair.getPrivate().getEncoded()));
PublicKey pubKey = getKey(base64EncodedEncryptionKey);
byte[] cipherText1 = do_RSAEncryption(plainText, pubKey);
System.out.println("Encrypted Text ===> "+ DatatypeConverter.printHexBinary(cipherText1));
PrivateKey privateKey = getPrivateKey(base64EccodedDecryptionKey);
String decryptedText1 = do_RSADecryption(cipherText1,privateKey);
System.out.println("DecryptedText ====>>> "+decryptedText1);
Error:-
java.security.spec.InvalidKeySpecException: Only RSAPrivate(Crt)KeySpec and PKCS8EncodedKeySpec supported for RSA private keys
at java.base/sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:389)
at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:247)
at java.base/java.security.KeyFactory.generatePrivate(KeyFactory.java:390)
at com.apple.ist.alloy.memsqlloader.service.Asymmetric.getPrivateKey(Asymmetric.java:96)
at com.apple.ist.alloy.memsqlloader.service.Asymmetric.main(Asymmetric.java:135)
Exception in thread "main" java.security.InvalidKeyException: No installed provider supports this key: (null)
at java.base/javax.crypto.Cipher.chooseProvider(Cipher.java:930)
at java.base/javax.crypto.Cipher.init(Cipher.java:1286)
at java.base/javax.crypto.Cipher.init(Cipher.java:1223)
at com.apple.ist.alloy.memsqlloader.service.Asymmetric.do_RSADecryption(Asymmetric.java:68)
at com.apple.ist.alloy.memsqlloader.service.Asymmetric.main(Asymmetric.java:137)
Private keys are encoded with PKCS8EncodedKeySpec. You should replace X509EncodedKeySpec with that.

BadPaddingException RSA Encrypt then decrypt in java

I have been given an RSA public Key and an RSA private key with OAEP SHA-256 padding. I am attempting to simply encrypt a random string and then decrypt it to assert the result is equalt to the original.
This is the public key i have been given:
-----BEGIN RSA PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq8tiBtDmkeS/ruY3rrkq
dz6Lc6XWFRbI/GjPtIokrtpM+Ujyv6wX8TBqY8e03gzh+eE7VUyEVPapDnceAqgJ
ZQah2h+N5AEQKqNDM4/1to1V0F+m1ISR7CIUU8dvU+bPk67DU5VkEtLxf+mW8/es
hy0u6oSB04WCDPNnh+9GDF7tN7lOzBH1FxKPWIb5Gqg6GoXS+KgvQhYEk0TajIBk
+mefzTv1D4HJlhFYybgY+/p3k4P2kM5HnbEtoVpz/PL9+94YVp5RBHTQHmk/3SAX
RkPP34IjY6LZqTJGWQGxc64Qci54ZJsq4wSTXvfdHgUWz7eX+v1jA+GLjFExNcYZ
nQIDAQAB
-----END RSA PUBLIC KEY-----
This is the private key I have been given:
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAUQiHdHuMBCnF
P/7RQoRWrp62dGWQLDLP9l+3KUMlSPheN2R5jHDZ/WEGJGF2WYKxaQvv5XCocdnt
uxVZTNM1PVyduokJaJzrSIj+jGWDd4hTWvVoS3vhds8u6W0jD3M4ayrF6c7NYuHc
tE5YLLIgK1DTn+ZZCr3VGbScISDJ/WPx3+1YTNQDvm+T7MfjhetJqqzWIsunMUiw
nQOQvkdjCVWpk+L10SaMrezixtIS5wfpOTjGIZ0w5VunvtsPxg1TkuvGURa9S3rS
7D3uhDPY+V8UDMpBPso3j7TGD5axlBJcpavWeF8qde3sWztmqUFQ3JDypZWGSAe2
d8e4mY65AgMBAAECggEAal8nwYxbHZnb5L892U7aVfuly7Nbzb+0pzRVwsBu5DuV
LL+kslpMvTYZqUUMJ2LhF/HLaXhVtMWsTYLSDx+gHu1+wbtAOtUDHlxzcaAEMhA2
dix0WqiNr6qAdCkmdWMBTu5vrSJigVW1KdcNElY+e+6ZeUQTK6L2Vt0t+cGVGkM4
K5PdHcGLR1BiAf3k4BguHE4TGGnqN9dF5Rn9nPP6C7QihWzGn15efD2dAXn3Kbho
dMIRgyYiO7uXPm2LrIjtldYb8tPus+V9SWT4hcgnJZrtd9atkqZrJ3dhQf9ZetGs
UwTCzHJ169NNbVyrjCbcy4Uht8Na+t/94Im9hI8n0QKBgQDO6tYnwh1hPg3E+4DY
xCiDAp7v3afJIvC9a1sBtif8KkzZTYH31ww+PRcfDPQUlk/MIDie0u6xIawnBYkC
oN1u9erojcvQbBP0GFylP5hNxYZbI7gPA/7AiGRxyezZPOiVMwdd5fCM7Wv4kucr
c1JCcvtPoDQcFFZOfI+wqqdWnQKBgQDt745Pvckt7/XL7wbfv4BV+cwpLNjc4/3k
ajOLtasgpT8mc0gUH2ejHhpkuhjSUpSTrlFB8EN1kAwmBYy0GOoO9967hm6twmqk
Q5L3OHJ96pYkf1rbyXNE1N7inh5Z3M1H5ONIaliAYLHXOzKsZvI5eUdKAJdSqFLo
uvVCwr4PzQKBgG6W3rzDJ9a4Rr24OgYg2RIkTXQgALQko4xpm2tPwxEoPoiJv2QK
ILYHCpuC3dU+/Qk5U2m3jPFI8OyuLask9RSABPwkBQGxMfztJF8BnVI7tvJxJceI
uBiJDT4v0RHOVvSfIFnUMnvvzRw+z6TObvGq6JyHIDK9v98U/etLWkKVAoGAIIxF
lmjqzUrm/8ep1A+5OYmbQQKug8D4aTeR54mpaCTSt6rLcF0/axPiHmdKn/LF+lG9
MdzxDXLwBn952OUTl4qWwGZKW6Cdv+yyfPkOyGS/tyxovGoZR5ArESr6Eebfefc4
lB5gDuerTDr/2o+WkQAjHV9pU9hMxyNUC5biMv0CgYEAiDlw8lBf3cQs6FxNXs9t
whWpfL0yY7WAONvhfFB0Dpsz52gGDCYRvJekGRz6jOlKDuXJ+Mm1AX4BaufMETI5
QseZxtVPIn+BXm0A1x8w/DifmE1JqQZmPCQPOh3eLx5nSn9LKGIbMgd17mfH3HhU
8WX2mzWjmRA3C/CzdGfCKSk=
-----END PRIVATE KEY-----
I am reading this key from a pem file "crypt_pkcs8.pem" but recive the public key as a byte array from a gRPC call.
Here is my Java code:
public class Encryption{
public static void main(String args){
ByteString publicKey = client.getPublicKey(nonce).getRSAEncryptionKey();
String strKeyPEM = "";
BufferedReader br = new BufferedReader(new FileReader("crypt_pkcs8.pem"));
String line;
while ((line = br.readLine()) != null) {
strKeyPEM += line+"\n";
}
br.close();
byte[] pt;
try {
pt = "h".getBytes("UTF-8");
byte[] ct =encrypt(publicKey, pt);
byte[] response= decrypt(strKeyPEM, ct);
assertEquals(pt, response);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static byte[] encrypt(ByteString rawKey ,byte[] message){
String strippedKey=stripKey(rawKey.toStringUtf8());
byte[] keyBytes = Base64.getDecoder().decode(strippedKey);
System.out.println(keyBytes.length);
Cipher cipher_RSA;
try {
cipher_RSA = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
PublicKey pk = keyFactory.generatePublic(spec);
System.out.println(pk.getAlgorithm()+" format : "+pk.getFormat());
cipher_RSA.init(Cipher.ENCRYPT_MODE, pk);
return cipher_RSA.doFinal(message);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
BadPaddingException | InvalidKeyException | InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public static byte[] decrypt(String rawKey ,byte[] message){
String strippedKey=stripPrivateKey(rawKey);
byte[] keyBytes = Base64.getDecoder().decode(strippedKey);
System.out.println(keyBytes.length);
Cipher cipher_RSA;
try {
cipher_RSA = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
PrivateKey pk = keyFactory.generatePrivate(spec);
System.out.println(pk.getAlgorithm()+" format : "+pk.getFormat());
cipher_RSA.init(Cipher.DECRYPT_MODE, pk);
return cipher_RSA.doFinal(message);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
BadPaddingException | InvalidKeyException | InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public static String stripKey(String key){
key = key.replace("-----BEGIN RSA PUBLIC KEY-----\n", "");
key = key.replace("-----END RSA PUBLIC KEY-----", "");
key = key.replace("\n", "");
return key;
}
public static String stripPrivateKey(String key){
key = key.replace("-----BEGIN PRIVATE KEY-----", "");
key = key.replace("-----END PRIVATE KEY-----", "");
key = key.replace("\n", "");
return key;
}
}
I cannot find anything obviously wrong with my actaul code so I believe this is to do with the keys not matching.
I also notice the header/footer is different on the public key and private key. From looking online this is because the public key is in PKCS#8 format.
Will I need to change the public key to pkcs#8 format as well? If so what is the easiest way to do this?
I have also been told I should be able to extract the public key (in pkcs8 format) from the private key given above. Can this be done easily?
If you can get a valid public key then the key is not in PKCS#8 format, it will be in X.509 (SubjectPublicKeyInfo) format as Java expects. However, your public and private keys do indeed not match. You can use the answer here to create the correct public key file from the private key file.
Java doesn't directly contain code to retrieve the public exponent from an RSAPrivateKey without CRT parameters. However, if you want a Java only solution you could cast the PrivateKey even further to RSAPrivateCrtKey which does contain a getPublicExponent method to retrieve the public exponent. Then you can use an RSA KeyFactory to generate a public key using RSAPublicKeySpec.
You could also parse the PEM file to retrieve the public key in Java using e.g. the Bouncy Castle API. But expect a steep learning curve if you do.

Android Encryption RSA InvalidKeyException

Dears,
I need help to understand why decryptString doesn't work and throw "java.security.InvalidKeyException: Need RSA private or public key". When call encrypt method, i use public key by the private key/certificate.
Thanks for any help!
public class KeysHandler {
/***
* Generate and store in AndroidKeyStore a security KeyPair keys.
* #param alias - Alias to create the key.
* #return KeyPair object with: private and public key.
*/
public static KeyPair generateKeyPair(String alias) {
KeyPair kp = null;
if (alias != null) {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
kpg.initialize(new KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_SIGN |
KeyProperties.PURPOSE_VERIFY |
KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.build());
kp = kpg.generateKeyPair();
} catch (NoSuchProviderException | NoSuchAlgorithmException | InvalidAlgorithmParameterException ex) {
kp = null;
}
}
return kp;
}
public static String encryptString(String alias, String textToEncrypt) {
String cipheredText = null;
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
// Encrypt the text
if(textToEncrypt != null && textToEncrypt.length() > 0) {
Cipher input = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
input.init(Cipher.ENCRYPT_MODE, privateKeyEntry.getCertificate().getPublicKey());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(
outputStream, input);
cipherOutputStream.write(textToEncrypt.getBytes("UTF-8"));
cipherOutputStream.close();
byte[] vals = outputStream.toByteArray();
cipheredText = Base64.encodeToString(vals, Base64.DEFAULT);
}
} catch (Exception e) {
cipheredText = null;
}
return cipheredText;
}
public static String decryptString(String alias, String cipheredText) {
String clearText = null;
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipheredText, Base64.DEFAULT)), output);
ArrayList<Byte> values = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
values.add((byte)nextByte);
}
byte[] bytes = new byte[values.size()];
for(int i = 0; i < bytes.length; i++) {
bytes[i] = values.get(i).byteValue();
}
clearText = new String(bytes, 0, bytes.length, "UTF-8");
} catch (Exception e) {
clearText = null;
}
return clearText;
}
}
Try omitting the cipher provider:
Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding");
Secondly, you can instantiate the provider first to make sure that works, then pass it along as the second argument to Cipher.getInstance(). The second argument can be either a String (provider name) or a Provider (object). Using the second might make debugging easier.

RSAPrivateKey returns RuntimeException

Im trying to get the RSA keys to OpenSSLRSAPublicKey and OPENSSLRSAPrivateKey format on Android.
The keys look like this (generated automatically, do not work):
Private key string:
MIICWwIBAAKBgHfvJ1jB80KZTaEYClqbM0znYlos0qTenOF+BSjC4DT31rCwLgMJ
5/c7jSUuzH34OypP8Z7sGMz4UIXzXRGUKXA0TFXvq3aKNMGa74SCB3AGJmjb4yvT
rXpTytfeuJsodJzBmwsCkgfkAYZBH06OJAxNPpqoUMUZHOg61hTHwm9nAgMBAAEC
gYBC8L3yYVaITo6won1s8wEgJGmV0TzE/udrSG5SwOppRgeTWNJlqcrKCHgQT92d
VcaYKETBIh/5j4NKMHo6zIqPpH7GxzNuG3Ua+pmi6VOcdFs7O071q6zAt9aLb/Dd
rs7gJb5/H2/LuJBbKInKb+c0IUMEQ9AFoAc70q+um4eJmQJBAOxugXf7LFlCrfun
TuR5eYVjLBM9pmVRMEYJcp9CH7qtTAKhdHAKgnZ7Sw3gTxtBi+msnm3zXwtzO/cY
Xjh+m7UCQQCB3E8xvJWICLpX/11saDUOZsoaC53A7SunptkbAyJ49yE8SVg3O92i
kqRBlFho1JL84vDZe10GXwxj6O1XwigrAkAAzfN01A73ksmCxLP5BQzLzmWU/y20
xIz0gA26yv/Oo85RZ/k8dFyzSIId3viF8DgoqGS1nRFiuZanpZaUfKHNAkAuQwDH
dCpE+u7/eE6c1wbHqaCn5Kl/WD5sDEldkSFPvKJPasWNb7tGNj1jy2gveEMg6evp
XkRGh8fPM+SRle5fAkEAmaQeOnryugbQBVOAj006jEQaidYsF8FNnKSAyxPQlbSC
Nee4pL/hKkjqtm5zKgEp8f0dHRhz5vb94EdLnl1DJA==
Public key string:
MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHfvJ1jB80KZTaEYClqbM0znYlos
0qTenOF+BSjC4DT31rCwLgMJ5/c7jSUuzH34OypP8Z7sGMz4UIXzXRGUKXA0TFXv
q3aKNMGa74SCB3AGJmjb4yvTrXpTytfeuJsodJzBmwsCkgfkAYZBH06OJAxNPpqo
UMUZHOg61hTHwm9nAgMBAAE=
This is my code:
public static RSAPrivateKey getPrivateKeyFromString(String key) throws IOException, GeneralSecurityException {
String privateKeyPEM = key;
privateKeyPEM = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----\n", "");
privateKeyPEM = privateKeyPEM.replace("-----END PRIVATE KEY-----", "");
byte[] encoded = Base64.decode(privateKeyPEM, Base64.DEFAULT);
KeyFactory kf = KeyFactory.getInstance("RSA");
///////// Line below is (RSA.java:37)
RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
return privKey;
}
public static RSAPublicKey getPublicKeyFromString(String key) throws IOException, GeneralSecurityException {
String publicKeyPEM = key;
publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----\n", "");
publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");
byte[] encoded = Base64.decode(publicKeyPEM, Base64.DEFAULT);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded));
return pubKey;
}
The interesting thing is that the pubKey returns this:
OpenSSLRSAPublicKey{modulus=9920c2.....,publicExponent=10001}
But the privKey gives me this exception:
W/System.err: java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0c0890ba:ASN.1 encoding routines:asn1_check_tlen:WRONG_TAG
W/System.err: at com.android.org.conscrypt.OpenSSLKey.getPrivateKey(OpenSSLKey.java:283)
W/System.err: at com.android.org.conscrypt.OpenSSLRSAKeyFactory.engineGeneratePrivate(OpenSSLRSAKeyFactory.java:64)
W/System.err: at java.security.KeyFactory.generatePrivate(KeyFactory.java:187)
W/System.err: at com.vladmarton.educomiit.RSA$override.getPrivateKeyFromString(RSA.java:37)
I browsed the stackoverflow for a long time but I did not find any working solution. I need to have them in the exact format as the pubKey, but cant get the private key to work.
public static PublicKey buildPublicKey() {
try {
byte[] keyBytes = Base64.decode(publicKey.getBytes(StandardCharsets.UTF_8), Base64.DEFAULT);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(spec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
Logger.e(Logger.TAG, e.getMessage());
}
return null;
}
private static PrivateKey buildPrivateKey() {
String key= privateKey.replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", "")
.replaceAll("\\s+", "").replaceAll("\\r+", "").replaceAll("\\n+", "");
try {
byte[] keyByteArray = Base64.decode(key, Base64.DEFAULT);
KeyFactory kf = KeyFactory.getInstance("RSA");
EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyByteArray);
return kf.generatePrivate(keySpec);
} catch (Exception e) {
Logger.e(Logger.TAG, e.getMessage());
}
return null;
}

RSA encryption fail on older Android device (4.0.3 in this case)

im pretty new to android development and i have the following method for encryption data using RSA(2048b):
public byte[] encryptData(String base64) throws GeneralSecurityException {
byte[] dataToEncrypt = base64.getBytes(Charset.forName("UTF-8")); //lenght == 90
try {
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(rsaKeys.getPublicModus(), rsaKeys.getPublicExpo());
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPublicKeySpec);
//default providers
//4.0.3 - BC (BouncyCastleProvider)
//4.4.2 - AndroidOpenSSL
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] encryptedData = cipher.doFinal(dataToEncrypt); //this throw exception
return encryptedData;
} catch (GeneralSecurityException e) {
throw e;
}
}
This block of code working on Android 4.4.2 like a magic. Problem comming with Android 4.0.3 where its always end with exception:
com.android.org.bouncycastle.crypto.DataLengthException: input too large for RSA cipher.
at com.android.org.bouncycastle.crypto.engines.RSACoreEngine.convertInput(RSACoreEngine.java:115)
at com.android.org.bouncycastle.crypto.engines.RSABlindedEngine.processBlock(RSABlindedEngine.java:95)
at com.android.org.bouncycastle.crypto.encodings.PKCS1Encoding.encodeBlock(PKCS1Encoding.java:184)
at com.android.org.bouncycastle.crypto.encodings.PKCS1Encoding.processBlock(PKCS1Encoding.java:132)
at com.android.org.bouncycastle.jce.provider.JCERSACipher.engineDoFinal(JCERSACipher.java:467)
at javax.crypto.Cipher.doFinal(Cipher.java:1106)
Im confuse whats wrong (data length and keysize is on both device same). I will be grateful for any clue. Thanks.
My RSAKeys class contains simple constructor and get/set for each field:
private BigInteger publicModus, publicExpo;
private BigInteger privateModus, privateExpo;
Im using this method for RSA key generation:
#SuppressLint("TrulyRandom")
public RSAKeys generateRSAKeys() throws NoSuchAlgorithmException, InvalidKeySpecException {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// Pullingout parameters which makes up Key
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec rsaPubKeySpec = keyFactory.getKeySpec(publicKey,
RSAPublicKeySpec.class);
RSAPrivateKeySpec rsaPrivKeySpec = keyFactory.getKeySpec(
privateKey, RSAPrivateKeySpec.class);
rsaKeys = new RSAKeys(
rsaPubKeySpec.getModulus(), rsaPubKeySpec.getPublicExponent(),
rsaPrivKeySpec.getModulus(), rsaPrivKeySpec.getPrivateExponent());
return rsaKeys;
} catch (NoSuchAlgorithmException e) {
throw e;
} catch (InvalidKeySpecException e) {
throw e;
}
}
I edited my code for using same message to encrypt base64 = "plain text"; and same RSA keys on both devices. Without any progress. Still getting error on device with Android 4.0.3.
Devices:
HTC Desire 610 - Android 4.4.2
HTC One V - Android 4.0.3
try to specific both algorithm and provider
// example how to generate key pair
class MyKeyPair {
private static final String ALGORITHM = "RSA";
private static final String PROVIDER ="BC";
private static final int STRENGTH = 2048;
private PrivateKey _privateKey;
private PublicKey _publicKey;
public PublicKey getPublicKey {return _publicKey;}
public MyKeyPair() {
generateKeyPair(STRENGTH,RSA,BC);
}
private void generateKeyPair(int keyLength, String algorithm,
String providerName) {
KeyPairGenerator keyPairGen =
KeyPairGenerator.getInstance(algorithm,providerName);
keyPairGen.initialize(keyLength);
KeyPair keyPair = keyPairGen.generateKeyPair();
_privateKey = keyPair.getPrivate();
_publicKey = keyPair.getPublic();
}
}

Categories