使用rsa密钥解密字符串

时间:2018-02-08 09:32:16

标签: java android security encryption bouncycastle

我使用json编码了一个简单的RSA public key数据,现在我正在尝试解码它。编码部分通过终端完成,解码正在以编程方式执行。为了验证加密文件的完整性,我通过终端解密它,它工作得很好。现在我正在尝试以编程方式解密文件,我正在尝试解密问题。我可以完美地读取private_key.pem文件并将其传递给Cipher以解密编码文件,但是在执行此操作时,我得到以下异常。

java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block
 at com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.engineDoFinal(CipherSpi.java:457)
 at javax.crypto.Cipher.doFinal(Cipher.java:1204)
 at com.benchmark.openssl.RSADecryption.decipherString(RSADecryption.java:295)
 at com.benchmark.openssl.RSADecryption.main(RSADecryption.java:263)
 at com.benchmark.MainActivity$1.onComplete(MainActivity.java:157)
 at io.reactivex.internal.operators.completable.CompletableObserveOn$ObserveOnCompletableObserver.run(CompletableObserveOn.java:90)
 at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:463)
 at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
 at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
 at java.util.concurrent.FutureTask.run(FutureTask.java:237)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
 at java.lang.Thread.run(Thread.java:841)

使用的OpenSSL命令:

openssl genrsa -out priv_key.pem 2048  
openssl rsa -pubout -in priv_key.pem -out pub_key.pem 
openssl rsautl -encrypt -in userdata.json -out user_encrypted_with_pub_key -inkey pub_key.pem –pubin
openssl rsautl -decrypt -in user_encrypted_with_pub_key -inkey priv_key.pem --> This is what I'm trying to do programmatically.

代码:

import org.spongycastle.util.io.pem.PemObject;
import org.spongycastle.util.io.pem.PemReader;
import android.util.Base64;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public static void main(String privateKeyPath, String encodedFilePath) throws FileNotFoundException,
            IOException, NoSuchAlgorithmException, NoSuchProviderException {
        Security.addProvider(new BouncyCastleProvider());

        String encodedString = readFileAsString(encodedStringPath);
        Timber.v("Encoded String: %s", encodedString);

        KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
        try {
            PrivateKey priv = generatePrivateKey(factory, privateKeyPath);
            Timber.i(String.format("Instantiated private key: %s", priv));
            decipherString(priv, encodedString);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
    }

    private static PrivateKey generatePrivateKey(KeyFactory factory,
                                                 String filename) throws InvalidKeySpecException,
            FileNotFoundException, IOException {
        PemFile pemFile = new PemFile(filename, false);
        byte[] content = pemFile.getPemObject().getContent();
        PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
        return factory.generatePrivate(privKeySpec);
    }

    private static void decipherString(PrivateKey privateKey, String encodedStringData) {
        byte[] dectyptedText = null;
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            dectyptedText = cipher.doFinal(encodedStringData.getBytes()); <---- EXCEPTION HERE
            Timber.w("Deciphered text is: %s", new String(dectyptedText));
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    static class PemFile {

        private PemObject pemObject;

        public PemFile(String filename, boolean isBase64) throws FileNotFoundException, IOException {
            PemReader pemReader = new PemReader(new InputStreamReader(new FileInputStream(filename)));
            try {
                this.pemObject = pemReader.readPemObject();
            } 
            catch (Exception e) {
                e.printStackTrace();
            }
            finally {
                pemReader.close();
            }
        }

        public PemObject getPemObject() {
            return pemObject;
        }
    }

userdata.json:

{
    "username":"umer",
    "password":"123456",
    "pin" : "123"
}

1 个答案:

答案 0 :(得分:1)

我通过一些反复试验弄明白,因为我对openssl知之甚少。无论如何,解密加密文件的过程应该如下。

终端:

String -> (Encrypt) -> Encrypted String -> (convert to base64) -> EncryptedBase64EncodedString -> (Decrypt) -> Original String

<强> Programmtically:

EncryptedBase64EncodedString -> (convert from base64 to normal string [Use Default parameters only! No Padding or other constants for decoding base64 string]) -> Pass private_key & decoded string to Cipher -> Profit.

结果代码是:

import org.spongycastle.util.io.pem.PemObject;
import org.spongycastle.util.io.pem.PemReader;

import android.util.Base64;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

public static void main(String privateKeyPath, String publicKeyPath, String encodedStringPath, boolean isPublicKeyAndDataBase64) throws FileNotFoundException,
            IOException, NoSuchAlgorithmException, NoSuchProviderException {
        Security.addProvider(new BouncyCastleProvider());

        String encodedString = readFileAsString(encodedStringPath);
        if(isPublicKeyAndDataBase64) {
            KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
            Timber.w("Encoded String converted from base64: %s", decodeBase64ToBytesa(encodedString));
            try {
                PrivateKey priv = generatePrivateKey(factory, privateKeyPath);
                Timber.i(String.format("Instantiated private key: %s", priv));
                decipherString(priv, decodeBase64ToBytesa(encodedString));
            } catch (InvalidKeySpecException e) {
                e.printStackTrace();
            }
            return;
        }
        else
            Timber.w("Encoded String: %s", encodedString);

        KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
        try {
            PrivateKey priv = generatePrivateKey(factory, privateKeyPath);
            Timber.i(String.format("Instantiated private key: %s", priv));
            decipherString(priv, encodedString.getBytes());
            PublicKey pub = generatePublicKey(factory, publicKeyPath);
            Timber.i(String.format("Instantiated public key: %s", pub));
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
    }

    private static PrivateKey generatePrivateKey(KeyFactory factory,
                                                 String filename) throws InvalidKeySpecException,
            FileNotFoundException, IOException {
        PemFile pemFile = new PemFile(filename, false);
        byte[] content = pemFile.getPemObject().getContent();
        PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
        return factory.generatePrivate(privKeySpec);
    }

    private static PublicKey generatePublicKey(KeyFactory factory,
                                               String filename) throws InvalidKeySpecException,
            FileNotFoundException, IOException {
        PemFile pemFile = new PemFile(filename, false);
        byte[] content = pemFile.getPemObject().getContent();
        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
        return factory.generatePublic(pubKeySpec);
    }

    private static void decipherString(PrivateKey privateKey, byte[] encodedStringData) {
        byte[] dectyptedText = null;
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            dectyptedText = cipher.doFinal(encodedStringData);
            Timber.w("Deciphered text is: %s", new String(dectyptedText));
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    static class PemFile {

        private PemObject pemObject;

        public PemFile(String filename, boolean isBase64) throws FileNotFoundException, IOException {
            PemReader pemReader = null;

            if(isBase64) {
                Timber.i("reading base64 encoded pem file. base64DecodedString: %s", decodeBase64(filename));
                pemReader = new PemReader(new StringReader(decodeBase64(filename)));
            }
            else
                pemReader = new PemReader(new InputStreamReader(
                        new FileInputStream(filename)));
            try {
                this.pemObject = pemReader.readPemObject();
            }
            catch (Exception e) {
                e.printStackTrace();
            }finally {
                pemReader.close();
            }
        }

        public PemObject getPemObject() {
            return pemObject;
        }
    }