Encrypt and decrypt a SecretKey with RSA public and private keys - java

I am trying to encrypt a secretKey with my publicKey, then decrypt it somewhere else with the private key. I can encrypt and decrypt fine, However I am getting a completely different key back when I do this.
Here is the code that creates the public/ private keypair
public static KeyPair generateKeyPair()
{
KeyPair returnPair = null;
try
{
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SunJSSE");
System.out.println("provider:" + kpg.getProvider().getName());
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
kpg.initialize(1024, random);
returnPair = kpg.generateKeyPair();
}catch(Exception e)
{
e.printStackTrace();
}
return returnPair;
}
I specified the SunJSSE provider, although I am not getting any different result than when I ran with DiffieHellman from SunJCE or the RSA/ SunRSASign provider. I am new to java security so these concepts are still a little above my head.
Here is the code I use to generate the secret key
public static SecretKey generateSecretKey(String keyPassword)
{
SecretKey key = null;
try
{
SecretKeyFactory method = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
//System.out.println("salt length: " + new SaltIVManager().getSalt().length);
PBEKeySpec spec = new PBEKeySpec(keyPassword.toCharArray(), new SaltIVManager().getSalt(), 10000, 128);
key = method.generateSecret(spec);
System.out.println("generate secret key length: " + key.getEncoded().length);
}catch(Exception e)
{
e.printStackTrace();
}
return key;
}
And here are the two methods I use to encrypt/ decrypt my secret key
public static byte[] encryptSecretKey(SecretKey secretKey, PublicKey publicKey)
{
byte[] encryptedSecret = null;
try
{
Cipher cipher = Cipher.getInstance("RSA/ECB/NOPADDING");
System.out.println("provider: " + cipher.getProvider().getName());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
System.out.println("original secret key: " + Base64.getEncoder().encodeToString(secretKey.getEncoded()) + " \n secretkey encoded length: " + secretKey.getEncoded().length);
encryptedSecret = cipher.doFinal(secretKey.getEncoded());
System.out.println("encrypted secret: " + Base64.getEncoder().encodeToString(encryptedSecret));
}catch(Exception e)
{
e.printStackTrace();
}
return encryptedSecret;
}
public static SecretKey decryptSecretKey(byte[] encryptedKey, PrivateKey privateKey)
{
SecretKey returnKey = null;
try
{
Cipher cipher = Cipher.getInstance("RSA/ECB/NOPADDING");
System.out.println("provider: " + cipher.getProvider().getName());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
System.out.println("encryptedkey length: " + encryptedKey.length);
byte [] encodedSecret = cipher.doFinal(encryptedKey);
System.out.println("encoded Secret after decrypt: " + Base64.getEncoder().encodeToString(encodedSecret));
returnKey = new SecretKeySpec(encodedSecret, 0, encodedSecret.length, "PBEWithMD5AndDES");
System.out.println("secret key: " + Base64.getEncoder().encodeToString(returnKey.getEncoded()));
System.out.println("secret key length post decrypt: " + returnKey.getEncoded().length);
}catch(Exception e)
{
e.printStackTrace();
}
return returnKey;
}
The RSA algorithm is the only one I have gotten to work with my keys. If I specify the DiffieHellman alg. for the keypair, I am unable to encrypt/ decrypt at all. If anyone has any insight into what I have done wrong, any help would be greatly appreciated. When I call this in its current state, I start with a secretkey of this value = cGFzczEyMw== and end with a key of this value after encryption/ decryption
SvMNufKu2JA4hnNEwuWdOgJu6FxnNmuLYzxENhTsGgFzc/i3kQIXbeVaJUkJck918BLCnm2u2QZCyVvJjYFXMLBFga0Zq0WMxSbIZvPz1J/EDi9dpsAkbFhLyBWmdDyPr+w7DMDsqHwKuA8y/IRKVINWXVrp3Hbt8goFZ0nGIlKVzMdJbGhNi3HZSAw4R6fXZNKOJ3nN6wDldzYerEaz2MhJqnZ3Dz4psA6gskomhjp/G0yhsGO8pllMcgD0jzhL86RGrBhjj04Bj0ps3AAACkQLcCwisso8dWigvR8NX9dnI0C/gc6FqmNenWI1/AoPgmcRyFdlO7A2i9JXoSj+YQ==

You first should know what you are trying to do before doing it:
RSA without padding is completely insecure;
you use a key for Password Based Encryption which only makes sense with - well - a password;
you come out with a DES key, which again is completely insecure;
you probably generate it with a salt, which is random, so the output is random.
The whole protocol doesn't make sense. That you're trying to encrypt directly with DH (a scheme to perform key agreement) shows that you haven't studied crypto enough.
With cryptography it's not about getting things to work. It's about getting things secure. You cannot do that by just trying things out. Learn at least the basics of cryptography then code.

The issue in fact was the way in which I was storing/ retrieving my keys. I had used a keystore for the private and a file for the public. The way in which I retrieved these keys was causing them to become malformed, thus the failure in my cipher and the need to run with NOPADDING in order to get any sort of output.
Here is the new storage code I am using for RSA keys- writing them to a file.
public static boolean saveKeys(Key privateKey, Key publicKey, char[] password, String alias)
{
boolean saved = false;
try
{
KeyPair kp = generateKeyPair();
KeyFactory kf = KeyFactory.getInstance("RSA");
if(privateKey != null)
{
File privKeyFile = new File(System.getProperty("user.home") + "/.etc/privkey");
if(!privKeyFile.exists())
{
privKeyFile.createNewFile();
}
System.out.println("private key: " + Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded()));
RSAPrivateKeySpec pubSpec = kf.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(System.getProperty("user.home") + "/.etc/privkey")));
oout.writeObject(pubSpec.getModulus());
oout.writeObject(pubSpec.getPrivateExponent());
oout.close();
}if(publicKey != null)
{
File pubKeyFile = new File(System.getProperty("user.home") + "/.etc/pubkey.pub");
if(!pubKeyFile.exists())
{
pubKeyFile.createNewFile();
}
System.out.println("public key: " + Base64.getEncoder().encodeToString(kp.getPublic().getEncoded()));
RSAPublicKeySpec pubSpec = kf.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(System.getProperty("user.home") + "/.etc/pubkey.pub")));
oout.writeObject(pubSpec.getModulus());
oout.writeObject(pubSpec.getPublicExponent());
oout.close();
}
}catch(Exception e)
{
e.printStackTrace();
}
return saved;
}

Related

Android RSA encryption with OAEP using SHA-256 for main and MGF1 digests

By specification I need to use "RSA/ECB/OAEPPadding" cipher with SHA-256 for both digests - the main digest and the MGF1 digest.
Android Cryptography suggests to initialize Cipher like this: cipher.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
In reality this is not working, because init(DECRYPT_MODE, ...) throws exception: InvalidAlgorithmParameterException, Unsupported MGF1 digest: SHA-256. Only SHA-1 supported.
Do anyone know, how to resolve this problem? Using another algorithm parameters in no option.
This is the code sample, run encryptDecrypt() to reproduce the error. Minimum api level is 23.
static void encryptDecrypt()
{
KeyPair keyPair = generateWrappingKeypair("MY_KEY");
try
{
Cipher cipher = getCipher(Cipher.ENCRYPT_MODE, keyPair.getPublic());
byte[] data = new byte[1]; // Just create the smallest data to encrypt
// Encryption goes well
byte[] encrypted = cipher.doFinal(new byte[1]);
// This line throws exception: "InvalidAlgorithmParameterException, Unsupported MGF1 digest: SHA-256. Only SHA-1 supported"
cipher = getCipher(Cipher.DECRYPT_MODE, keyPair.getPrivate());
byte[] decrypted = cipher.doFinal(encrypted);
if (!Arrays.equals(data, decrypted))
{
throw new RuntimeException("Decrypted data is not equals to raw data");
}
}
catch (Exception ex)
{
Log.e(TAG, "Encryption error, exception: " + ex.getClass().getSimpleName() + " " + ex.getMessage());
}
}
static KeyPair generateWrappingKeypair(String aliasOfKey)
{
Calendar dateValidFrom = Calendar.getInstance();
Calendar dateValidTo = Calendar.getInstance();
dateValidTo.add(Calendar.YEAR, 1);
KeyGenParameterSpec specOfKey = new KeyGenParameterSpec.Builder(aliasOfKey, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F0))
.setKeySize(4096)
.setKeyValidityStart(dateValidFrom.getTime())
.setKeyValidityEnd(dateValidTo.getTime())
.setCertificateSerialNumber(BigInteger.ONE)
.setCertificateSubject(new X500Principal(String.format("CN=%s", aliasOfKey)))
.setDigests(KeyProperties.DIGEST_SHA256) // Setting two SHA256 digests here don't make any difference
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
.build();
try
{
KeyPairGenerator generatorOfKeyPairs = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
generatorOfKeyPairs.initialize(specOfKey);
return generatorOfKeyPairs.generateKeyPair();
}
catch (GeneralSecurityException ex)
{
Log.e(TAG, "Cannot generate keypair, exception: " + ex.getClass().getSimpleName() + " " + ex.getMessage());
return null;
}
}
static Cipher getCipher(int operationMode, Key key) throws GeneralSecurityException
{
// AndroidKeyStoreBCWorkaround should be used here from API 23 for Cipher to be compatible with AndroidKeyStore keys
// Any other security provider is not compatible
final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding", "AndroidKeyStoreBCWorkaround");
cipher.init(operationMode, key, new OAEPParameterSpec(KeyProperties.DIGEST_SHA256, "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
return cipher;
}

Why is RSA encryption in Java producing different length ciphertext than C#

I am AES encrypting some text using a randomly generated key and then RSA encrypting that key with a private key so that I can upload it to a database.
The RSA keys are generated using KeyPairGenerator in Java and saved as a file. Keys are read in using File.ReadAllBytes().
When I do this in Java everything works perfectly and the encrypted key is always 172 bytes, but when I do it in C# the encrypted key is always 844 bytes. I'm pretty sure the text is being encrypted properly using AES, but something is going wrong with the RSA encryption.
I have checked the key sizes in Java and C# and they always match. Literally, the only difference I can see is the RSA encrypted ciphertext length, which makes the data unusable. I believe it has something to do with padding, but I don't know how to fix it.
Java
public String encryptText(String msg, PrivateKey key)
throws NoSuchAlgorithmException, NoSuchPaddingException,
UnsupportedEncodingException, IllegalBlockSizeException,
BadPaddingException, InvalidKeyException {
KeyGenerator generator;
this.cipher.init(Cipher.ENCRYPT_MODE, key); //cipher is initialized earlier with this.cipher = Cipher.getInstance("RSA");
try {
generator = KeyGenerator.getInstance(AES);
generator.init(128); // The AES key size in number of bits
SecretKey secKey = generator.generateKey();
Cipher aesCipher = Cipher.getInstance(AES);
aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
String encText = Base64.getEncoder().encodeToString(aesCipher.doFinal(msg.getBytes("UTF-8")));
String encKey = Base64.getEncoder().encodeToString(cipher.doFinal(secKey.getEncoded()));
return "(" + encText + ")" + encKey;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
C#
public String EncryptText(byte[] privateKeyBytes, string msg)
{
try
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = RSA.ExportParameters(false);
RSAKeyInfo.Modulus = privateKeyBytes;
RSA.ImportParameters(RSAKeyInfo);
RijndaelManaged aes = new RijndaelManaged();
aes.BlockSize = 128;
aes.KeySize = 128;
aes.Mode = CipherMode.ECB;
byte[] keyGenerated = aes.Key;
string keyStr = Convert.ToBase64String(keyGenerated);
byte[] keyArr = Convert.FromBase64String(keyStr);
byte[] KeyArrBytes16Value = new byte[16];
Array.Copy(keyArr, KeyArrBytes16Value, 16);
aes.Key = KeyArrBytes16Value;
ICryptoTransform encrypto = aes.CreateEncryptor();
byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(msg);
byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length);
string encText = Convert.ToBase64String(CipherText);
string encKey = Convert.ToBase64String(RSA.Encrypt(aes.Key, true));
return "(" + encText + ")" + encKey;
}
catch (CryptographicException e)
{
Console.WriteLine("FAILED: " + e.Message);
}
return null;
}
UPDATE
Thanks to Henno for pointing out that the problem was in how I was reading the key. I ended up using Bouncy Castle to handle the RSA encryption in C#. I also changed my java code to encrypt with the public key instead of the private key.
New C#
public String EncryptText(byte[] keyBytes, string msg)
{
try
{
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
RSAParameters rsaParameters = new RSAParameters();
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
RijndaelManaged aes = new RijndaelManaged();
aes.BlockSize = 128;
aes.KeySize = 128;
aes.Mode = CipherMode.ECB;
byte[] keyGenerated = aes.Key;
string keyStr = Convert.ToBase64String(keyGenerated);
byte[] keyArr = Convert.FromBase64String(keyStr);
byte[] KeyArrBytes16Value = new byte[16];
Array.Copy(keyArr, KeyArrBytes16Value, 16);
aes.Key = KeyArrBytes16Value;
ICryptoTransform encrypto = aes.CreateEncryptor();
byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(msg);
byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length);
string encText = Convert.ToBase64String(CipherText);
string encKey = Convert.ToBase64String(rsa.Encrypt(aes.Key, false));
return "(" + encText + ")" + encKey;
}
catch (CryptographicException e)
{
Console.WriteLine("FAILED: " + e.Message);
}
return null;
}
What seems to go wrong is that you read in the saved "private key file" in C#, presumably in the variable privateKeyBytes (but your code is incomplete, so I'm guessing) and then do RSAKeyInfo.Modulus = privateKeyBytes, which is weird and cryptographically implausible. You should instantiate some kind of RSA class in C# as well, based on the bytes you read in, which is what I think you're trying to do in the beginning of the C# code (first four lines). I think there should be another API for that, looking around in the docs:
RSA.ImportParameters(RSAKeyInfo) and then maybe set RSAKeyInfo from those bytes, but it's not the modulus. The read in bytes should be PKCS1 format or something similar, maye base64 encoded in file, or raw etc. You'd have to look into what format Java uses to export full keys to disk.
You use the raw bytes you read in from file as a modulus, which is surely going to give trouble and gives a "key" that is invalid and much too big as well.

RSA 512 bit implementation in android with NO PADDING

My question is that on how to use RSA 512 bit in Android; I was able to generate the public and private keys by looking up on the internet but not sure if its with NO padding as I could not find any solution for it.The public key would be sent to the server also with the integer encrypted with the private key.
I am new to it so it would be great to have some help. Thanks!
genreateKeys("RSA",512)
The following code:
private static void generateKeys(String keyAlgorithm, int numBits) {
try {
// Get the public/private key pair
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(keyAlgorithm);
keyGen.initialize(numBits);
KeyPair keyPair = keyGen.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
System.out.println("\n" + "Generating key/value pair using " + privateKey.getAlgorithm() + " algorithm");
// Get the bytes of the public and private keys
byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();
// Get the formats of the encoded bytes
String formatPrivate = privateKey.getFormat(); // PKCS#8
String formatPublic = publicKey.getFormat(); // X.509
System.out.println("Private Key : " + HttpRequest.Base64.encode(String.valueOf(privateKeyBytes)));
System.out.println("Public Key : " + HttpRequest.Base64.encode(String.valueOf(publicKeyBytes)));
// The bytes can be converted back to public and private key objects
KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey2 = keyFactory.generatePrivate(privateKeySpec);
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
PublicKey publicKey2 = keyFactory.generatePublic(publicKeySpec);
// The original and new keys are the same
System.out.println(" Are both private keys equal? " + privateKey.equals(privateKey2));
System.out.println(" Are both public keys equal? " + publicKey.equals(publicKey2));
} catch (InvalidKeySpecException specException) {
System.out.println("Exception");
System.out.println("Invalid Key Spec Exception");
} catch (NoSuchAlgorithmException e) {
System.out.println("Exception");
System.out.println("No such algorithm: " + keyAlgorithm);
}
}
It gives me the output of public and private keys but its not with NO PADDING also how can I use the private key to encrypt my integer value?

KeyPairGeneratorSpec replacement with KeyGenParameterSpec.Builder equivalents - Keystore operation failed

The following method is deprecated
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
.setAlias(alias)
.setSubject(new X500Principal("CN=Sample Name, O=Android Authority"))
.setSerialNumber(BigInteger.ONE)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build();
generator.initialize(spec);
The replacement I came upon looks like this
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
generator.initialize(new KeyGenParameterSpec.Builder
(alias, KeyProperties.PURPOSE_SIGN)
.setDigests(KeyProperties.DIGEST_SHA256)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
.build());
Although I am able to use this to generate a keypair entry and encrypt the value, I am unable to decrypt it
public void encryptString(String alias) {
try {
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();
String initialText = startText.getText().toString();
if(initialText.isEmpty()) {
Toast.makeText(this, "Enter text in the 'Initial Text' widget", Toast.LENGTH_LONG).show();
return;
}
//Security.getProviders();
Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidKeyStoreBCWorkaround");
inCipher.init(Cipher.ENCRYPT_MODE, publicKey);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(
outputStream, inCipher);
cipherOutputStream.write(initialText.getBytes("UTF-8"));
cipherOutputStream.close();
byte [] vals = outputStream.toByteArray();
encryptedText.setText(Base64.encodeToString(vals, Base64.DEFAULT));
} catch (Exception e) {
Toast.makeText(this, "Exception " + e.getMessage() + " occured", Toast.LENGTH_LONG).show();
Log.e(TAG, Log.getStackTraceString(e));
}
}
public void decryptString(String alias) {
try {
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidKeyStoreBCWorkaround");
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());
String cipherText = encryptedText.getText().toString();
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipherText, 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();
}
String finalText = new String(bytes, 0, bytes.length, "UTF-8");
decryptedText.setText(finalText);
} catch (Exception e) {
Toast.makeText(this, "Exception " + e.getMessage() + " occured", Toast.LENGTH_LONG).show();
Log.e(TAG, Log.getStackTraceString(e));
}
in the decrypt method, the following command fails:
Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidKeyStoreBCWorkaround");
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());
with
java.security.InvalidKeyException: Keystore operation failed
I think it has to do with the KeyGenParamaterSpec.Builder has incorrect conditions, similarly that the encrypt Cipher types are incorrect strings, same thing in the decrypt function.
But this can all be traced back to the use of the new KeygenParameterSpec.Builder, as using the older deprecated method allows me to encrypt and decrypt.
How to fix?
As Alex mentioned one missing piece is KeyProperties.PURPOSE_DECRYPT other one is setSignaturePaddings instead for that you have to use setEncryptionPaddings method. Here is the sample snippet.
new KeyGenParameterSpec.Builder(ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
// other options
.build()
Refer documentation for more information.
It's hard to be 100% sure given that you didn't provide a full stack trace of the exception.
Your code generates the private key such that it is only authorized to be used for signing, not decrypting. Encryption works fine because it does not use the private key -- it uses the public key and Android Keystore public keys can be used without any restrictions. Decryption fails because it needs to use the private key, but your code did not authorize the use of the private key for decryption.
It looks like the immediate fix is to authorize the private key to be used for decryption. Thia is achieved by listing KeyProperties.PURPOSE_DECRYPT when invoking the KeyGenParameterSpec.Builder constructor. If the key shouldn't be used for signing, remove KeyProperties.PURPOSE_SIGN from there as well as remove setSignaturePaddings.
You'll also need to authorize the private key use with PKCS1Padding: invoke setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)

RSA Encrypted chiper text to string and decrypting throwing javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes

private static String decrypt(String cipherString, PrivateKey key) {
byte[] dectyptedText = null;
byte[] stringText = null;
try {
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance(ALGORITHM);
//chiper init in encrypt mode
cipher.init(Cipher.ENCRYPT_MODE, key);
//tried to get bytes out of encrypted string
stringText = cipher.doFinal(cipherString.getBytes());
// decrypt the text using the private key
cipher.init(Cipher.DECRYPT_MODE, key);
dectyptedText = cipher.doFinal(stringText);
} catch (Exception ex) {
ex.printStackTrace();
}
return new String(dectyptedText);
}
I want to convert the cipher text into bytes generated by the encryptor to a string and store in a database. Then get the string and decrypt it whenever its needed. Is there anyone that could help me solving the issue I'm having?
I does not make sense to convert the byte-Array to String.
You have to either save the bytes directly (which would require an appropriate column in the database, for example BLOB), or you could encode the byte-Array, for example using Base64 (I would recommend the latter).
(If your problems are with the "public-crypto thingy", you may want to use the public key to encrypt, but the private key to decrypt. If you dont know what that means, check out some literature about public-key crypto, please.)
Since your problem seems to be with your key, you possibly need a public key and a private key, not only a private key.
Have a look at this simple RSA demo:
encryptionAlgorithm = "RSA/ECB/PKCS1Padding";
algorithm = "RSA";
try {
SecureRandom random = SecRandom.getDefault();
// Since you are working with asymmetric crypto, you need a keypair:
KeyPairGenerator kpg = KeyPairGenerator.getInstance(algorithm);
kpg.initialize(2048, random);
KeyPair kp = kpg.generateKeyPair();
// encrypting something with asymmetric crypto needs a public key:
Cipher cipher1 = Cipher.getInstance(encryptionAlgorithm);
cipher1.init(Cipher.ENCRYPT_MODE, kp.getPublic());
byte[] text = "This is a test".getBytes("ASCII");
System.out.println("text = " +(new String(text)));
byte[] ciphertext = cipher1.doFinal(text);
// here you could store & load your sipertext
System.out.println("ciphertext = " + ciphertext);
// decrypting something with asymmetric crypto needs a private key:
Cipher cipher2 = Cipher.getInstance(encryptionAlgorithm);
cipher2.init(Cipher.DECRYPT_MODE, kp.getPrivate());
byte[] cleartext = cipher2.doFinal(ciphertext);
System.out.println("cleartext = " +(new String(cleartext)));
} catch (Exception e) {
e.printStackTrace();
}

Categories

Resources