KeyPairGeneratorSpec replacement with KeyGenParameterSpec.Builder equivalents - Keystore operation failed - java

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)

Related

Decrypting text file in openssl:-Error:EVP_DecryptFinal_ex:wrong final block length:evp_enc.c:518:

I'm writing a small application to learn more of encryption/decryption.
From my code I am generating AES key and then encrypting text file with AES key.After that I am encrypting AES key using RSA public key.
Below is the code snippet
SecretKey secretAesKey ;
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
secretAesKey = keyGen.generateKey();
if (secretAesKey != null) {
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, secretAesKey);
long aesEncryptStartTime = SystemClock.elapsedRealtime();
CipherInputStream aesCis = new CipherInputStream(fis, aesCipher);
int read;
byte[] buffer = new byte[4096];
while ((read = aesCis.read(buffer)) != -1) {
aesFos.write(buffer, 0, read);
aesFos.flush();
}
// Encrypt the generated key
if (!encKeyFile.exists()) {
encKeyFile.createNewFile();
}
try {
byte[] encryptedAesKey = null;
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
rsaCipher.init(Cipher.ENCRYPT_MODE, readRsaPublicKeyFromResource(context));
encryptedAesKey = rsaCipher.doFinal(secretAesKey.getEncoded());
rsaFos.write(encryptedAesKey);
rsaFos.flush();
} catch (Exception e) {
Log.e(LOG_TAG, "RSA encryption error", e);
} finally {
rsaFos.close();
}
During decryption first decrypting AES key with RSA private key, from following code
FileInputStream keyFis = new FileInputStream(encKeyFile);
byte[] encKey = new byte[keyFis.available()];
keyFis.read(encKey);
keyFis.close();
SecretKey key = null;
PrivateKey privKey = readRsaPrivateKeyFromResource(context);
Cipher cipher = null;
try
{
// initialize the cipher...
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privKey);
// generate the aes key!
key = new SecretKeySpec (cipher.doFinal(encKey), "AES" );
String stringKey = Base64.encodeToString(key.getEncoded(), Base64.DEFAULT);
try {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput("aesDecrypted.key", Context.MODE_PRIVATE));
outputStreamWriter.write(stringKey);
outputStreamWriter.close();
}
catch (IOException e) {
Log.e("Exception", "File write failed: " + e.toString());
}
I am getting decrypted AES key for example "ah3ZWMieji6KtSav6gaayTvsEID2vpp589wdChTLmZs="
After converting it into hex value it is as follows. "6A1DD958C89E8E2E8AB526AFEA069AC93BEC1080F6BE9A79F3DC1D0A14CB999B"
Trying to decrypt text file with generated hex key in terminal
For e.g:
openssl aes-256-cbc -d -a -iv 0 -in encrypt.txt -out decrypt.txt -K
6A1DD958C89E8E2E8AB526AFEA069AC93BEC1080F6BE9A79F3DC1D0A14CB999B
I am getting following error
bad decrypt
7560:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:evp_enc.c:518:
Why would this be, and further, what am I doing incorrectly?
If anybody could help, I'd be very thankful.
You have multiple problems with your code, here is a non-exhaustive list:
Java automatically generates a random IV for you, but you forgot to save it for decryption (cipher.getParameters().getParameterSpec(IvParameterSpec.class));). The IV is not secret. Usually, it is sent along with the ciphertext.
Using keyFis.available() is a bad idea, because a stream doesn't tell you how big the underlying file is, but rather how many bytes are left in its internal buffer. Use a different technique to get the size of the file.
You've tried to implement hybrid encryption. When decrypting you need to reverse the process: first use RSA to decrypt the AES key and then use AES to decrypt the actual data.

Encrypt and decrypt a SecretKey with RSA public and private keys

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;
}

Base64 encoded string to Public Key using RSA From C# to Java

I am converting legacy application from .net to java. Legacy method using encryption using public key.
string text = "<base64encodedstring here>";
IBuffer buffer = CryptographicBuffer.DecodeFromBase64String(text);
AsymmetricKeyAlgorithmProvider asymmetricKeyAlgorithmProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.get_RsaPkcs1());
CryptographicKey cryptographicKey = asymmetricKeyAlgorithmProvider.ImportPublicKey(buffer, 3);
IBuffer buffer2 = CryptographicBuffer.ConvertStringToBinary(data, 0);
IBuffer buffer3 = CryptographicEngine.Encrypt(cryptographicKey, buffer2, null);
byte[] array;
CryptographicBuffer.CopyToByteArray(buffer3, ref array);
//return CryptographicBuffer.EncodeToBase64String(buffer3);
Here is my Java code to convert the given text into the public key
public static PublicKey getKey(String key) throws Exception{
try{
byte[] byteKey = Base64.getDecoder().decode(key);
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
KeyFactory kf = KeyFactory.getInstance("RSA","BC");
return kf.generatePublic(X509publicKey);
}
catch(Exception e){
throw e;
}
}
Here is my main method
public static void main(String[] args) {
String text = "base64encodedstring";
try {
Security.addProvider(new BouncyCastleProvider());
decode(text);
PublicKey pubKey=getKey(text);
byte[] input = "plaintext".getBytes();
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherText = cipher.doFinal(input);
System.out.println("cipher: " + new String(cipherText));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
But When I try to get the public key I get the exception below
java.security.spec.InvalidKeySpecException: encoded key spec not recognised
at org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi.engineGeneratePublic(Unknown Source)
at org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi.engineGeneratePublic(Unknown Source)
at java.security.KeyFactory.generatePublic(Unknown Source)
at com.test.EncryptionUtil.getKey(EncryptionUtil.java:38)
at com.test.EncryptionUtil.main(EncryptionUtil.java:60)
Am I doing something wrong? I am new to cryptography.
With some more research I found the way how it is doing in C#, but not able to convert it into java
public static CryptographicKey GetCryptographicPublicKeyFromCert(string strCert)
{
int length;
CryptographicKey CryptKey = null;
byte[] bCert = Convert.FromBase64String(strCert);
// Assume Cert contains RSA public key
// Find matching OID in the certificate and return public key
byte[] rsaOID = EncodeOID("1.2.840.113549.1.1.1");
int index = FindX509PubKeyIndex(bCert, rsaOID, out length);
// Found X509PublicKey in certificate so copy it.
if (index > -1)
{
byte[] X509PublicKey = new byte[length];
Array.Copy(bCert, index, X509PublicKey, 0, length);
AsymmetricKeyAlgorithmProvider AlgProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptKey = AlgProvider.ImportPublicKey(CryptographicBuffer.CreateFromByteArray(X509PublicKey));
}
return CryptKey;
}
What is the purpose of EncodeOID method and how it can be achieved in Java. The link below explains the creation of base64 encoded public key string and decode it in C#
http://blogs.msdn.com/b/stcheng/archive/2013/03/12/windows-store-app-how-to-perform-rsa-data-encryption-with-x509-certificate-based-key-in-windows-store-application.aspx
There is no direct way to read microsoft Capi1PublicKey into java. I first converted the Capi1PublicKey to X509-encoded public key in WinRT. then I used created key in java.
Obviously the key isn't X509-encoded. Find out how it is encoded and use an appropriate KeySpec.
C# uses AsymmetricAlgorithmNames.get_RsaPkcs1 you need to find equivalent for your JAVA code.
You may want to have look at this Import Public RSA Key From Certificate

Android AES Encryption from C# to Java

I am converting my C# encryption code to Android.
I am facing issue like I am not able to encrypt the text as same as C#.
Below I copy paste both code.
Both are working code regarding using it you can use any password & any plain text .You will find both have different output.
C# CODE
System.security.Cryptography.RijndaelManaged AES = new System.Security.Cryptography.RijndaelManaged();
System.Security.Cryptography.MD5CryptoServiceProvider Hash_AES = new System.Security.Cryptography.MD5CryptoServiceProvider();
final MessageDigest Hash_AES = MessageDigest.getInstance("MD5");
String encrypted = "";
try {
byte[] hash = new byte[32];
byte[] temp = Hash_AES.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(pass));
final byte[] temp = Hash_AES.digest(pass.getBytes("US-ASCII"));
Array.Copy(temp, 0, hash, 0, 16);
Array.Copy(temp, 0, hash, 15, 16);
AES.Key = hash;
AES.Mode = System.Security.Cryptography.CipherMode.ECB;
System.Security.Cryptography.ICryptoTransform DESEncrypter = AES.CreateEncryptor();
byte[] Buffer = System.Text.ASCIIEncoding.ASCII.GetBytes(input);
encrypted = Convert.ToBase64String(DESEncrypter.TransformFinalBlock(Buffer, 0, Buffer.Length));
} catch (Exception ex) {
}
return encrypted;
Here is my Android java code.
ANDROID JAVA CODE
private static String TRANSFORMATION = "AES/ECB/NoPadding";
private static String ALGORITHM = "AES";
private static String DIGEST = "MD5";
byte[] encryptedData;
public RijndaelCrypt(String password,String plainText) {
try {
//Encode digest
MessageDigest digest;
digest = MessageDigest.getInstance(DIGEST);
_password = new SecretKeySpec(digest.digest(password.getBytes()), ALGORITHM);
//Initialize objects
_cipher = Cipher.getInstance(TRANSFORMATION);
_cipher.init(Cipher.ENCRYPT_MODE, _password);
encryptedData = _cipher.doFinal(text);
} catch (InvalidKeyException e) {
Log.e(TAG, "Invalid key (invalid encoding, wrong length, uninitialized, etc).", e);
return null;
} catch (InvalidAlgorithmParameterException e) {
Log.e(TAG, "Invalid or inappropriate algorithm parameters for " + ALGORITHM, e);
return null;
} catch (IllegalBlockSizeException e) {
Log.e(TAG, "The length of data provided to a block cipher is incorrect", e);
return null;
} catch (BadPaddingException e) {
Log.e(TAG, "The input data but the data is not padded properly.", e);
return null;
}
return Base64.encodeToString(encryptedData,Base64.DEFAULT);
}
Should I need to use "US-ASCII" in pass or does it take it?
Use the same mode of operation: either ECB or CBC
Use the same character set: it's best to stick to "UTF-8"
Use the same key: in the C# code you're doubling the 128-bit key to 256 bits
When using CBC with a random IV, it is expected that the ciphertext differs for the same plaintext. The decryption is the operation that determines whether you succeeded.
Note that ECB is not semantically secure. Use CBC with a random IV. The IV doesn't have to be secret, so you can just prepend it to the ciphertext and slice it off before decryption.
It's better to use an authenticated mode like GCM or EAX or if it's not provided an encrypt-then-MAC scheme. It's hard to implement it correctly yourself so stick to some library that does this for you like RNCryptor.

How do I use use openssl to encrypt (not sign) using the private key, as is possible in Java?

I have a java program which RSA encrypts data with a private key:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
PrivateKey privateKey = null;
PublicKey publicKey = null;
// Load certificate from keystore
try {
FileInputStream keystoreFileInputStream = new FileInputStream("keystore.jks");
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(keystoreFileInputStream, "passphrase".toCharArray());
try {
privateKey = (PrivateKey) keystore.getKey("idm_key", "passphrase".toCharArray());
} catch (UnrecoverableKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (Exception e) {
// TODO broad exception block
e.printStackTrace();
}
// Make the encrypted data.
byte[] toEncrypt = "Data to encrypt".getBytes();
byte[] encryptedData = null;
// Perform private key encryption
try {
// Encrypt the data
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
encryptedData = cipher.doFinal(toEncrypt);
} catch (Exception e) {
// TODO broad exception block
e.printStackTrace();
}
I have the need to do the same thing using openssl. Here is the code I tried:
uint8_t *encryptedBytes = NULL;
const char* data = "Data to enrypt";
char *private_key_file_name = "privatekey.pem"
FILE *fp = fopen(private_key_file_name, "r");
RSA *rsa = RSA_new();
PEM_read_RSAPrivateKey(fp, &rsa, 0, "passphase");
size_t encryptedBytesSize = RSA_size(rsa);
encryptedBytes = malloc(encryptedBytesSize * sizeof(uint8_t));
memset((void *)encryptedBytes, 0x0, encryptedBytesSize);
fclose(fp);
int result = RSA_private_encrypt(strlen(data), data, encryptedBytes, rsa,RSA_PKCS1_PADDING);
This is not producing the same output as the Java implementation. Instead, it produces the output that is gotten by signing the data in Java, i.e.,
Signature rsa = Signature.getInstance("RSA");
rsa.initSign(privateKey);
rsa.update(toEncrypt);
byte [] signed = rsa.sign();
Though this is what I would expect given the documentation for RSA_private_encrypt, it's not what I need. Is there a way to replicate what the java code is doing with openssl?
I think you are confused. you don't "encrypt" data with a private key. That's worthless, as anyone can decrypt it. You sign with the private key (so anyone can verify it) and encrypt with the public key (so that only the holder of the private key can decrypt it). That is why the openssl API has RSA_public_encrypt which does encryption and RSA_private_encrypt which does signing.
You don't need to use OpenSSL in Java at all, whatever it is that you're trying to do. Java has its own crypto libraries. See the JCE reference and the javax.crypto package.

Categories

Resources