使用私钥的Android中的RSA解密

时间:2016-07-12 17:45:23

标签: android encryption rsa private-key

我在Android中使用加密 - 解密分别使用公钥和私钥。我将两个密钥保存在RAW文件夹中作为文件。加密工作完美,但对于解密,它总是会出现以下错误:

java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag

我附上我用过的代码段:

public class AppUtils {


public static String encryptString(String value, Context context){
    byte[] encodedBytes = null;
    try {
        //Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE,  getPublicKey(context) );
        encodedBytes = cipher.doFinal(value.getBytes());
    } catch (Exception e) {
        e.printStackTrace();
    }

    return Base64.encodeToString(encodedBytes, Base64.DEFAULT);
}

public static String decryptString(String value, Context context){
    byte[] decodedBytes = null;
    try {
        //Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
        Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        c.init(Cipher.DECRYPT_MODE,  getPrivateKey(context) );
        decodedBytes = c.doFinal(Base64.decode(value, Base64.DEFAULT));
    } catch (Exception e) {
        e.printStackTrace();
    }

    return new String(decodedBytes);
}


public static PrivateKey getPrivateKey(Context context){

    // reads the key_public key stored in a file
    InputStream is = context.getResources().openRawResource(R.raw.key_private);
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    List<String> lines = new ArrayList<String>();
    String line = null;

    try {


        while ((line = br.readLine()) != null)
            lines.add(line);


        // removes the first and last lines of the file (comments)
        if (lines.size() > 1 && lines.get(0).startsWith("-----") && lines.get(lines.size()-1).startsWith("-----")) {
           lines.remove(0);
         lines.remove(lines.size()-1);
        }

        // concats the remaining lines to a single String
        StringBuilder sb = new StringBuilder();
        for (String aLine: lines)
            sb.append(aLine);
        String keyString = sb.toString();

        byte [] encoded = Base64.decode(keyString, Base64.DEFAULT);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);

        PrivateKey myPrivKey = keyFactory.generatePrivate(keySpec);

        return myPrivKey;

    }catch (Exception e){

        e.printStackTrace();
    }
    return null;
}

public static PublicKey getPublicKey(Context context){

    // reads the key_public key stored in a file
    InputStream is = context.getResources().openRawResource(R.raw.key_public);
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    List<String> lines = new ArrayList<String>();
    String line = null;


    try {


        while ((line = br.readLine()) != null)
            lines.add(line);

        // removes the first and last lines of the file (comments)
        if (lines.size() > 1 && lines.get(0).startsWith("-----") && lines.get(lines.size()-1).startsWith("-----")) {
            lines.remove(0);
            lines.remove(lines.size()-1);
        }

        // concats the remaining lines to a single String
        StringBuilder sb = new StringBuilder();
        for (String aLine: lines)
            sb.append(aLine);
        String keyString = sb.toString();

        // converts the String to a PublicKey instance
        byte[] keyBytes = Base64.decode(keyString, Base64.DEFAULT);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey key = keyFactory.generatePublic(spec);

        return key;
    }catch (Exception e){
            e.printStackTrace();
    }

    return null;
}
}

最后,我从MainActivity.java中调用所需的函数,如下所示:

String encryptedString =  AppUtils.encryptString("SHANKAR", MainActivity.this);

Log.d("DX1", " Encrypted String " + encryptedString );


String decryptedString =  AppUtils.decryptString(encryptedString, MainActivity.this);

Log.d("DX1", " decrypted String " + decryptedString );

我看到了,我正确地获得了加密字符串,但在解密时声明:

PrivateKey myPrivKey = keyFactory.generatePrivate(keySpec);

向我提出上述错误。但我可以使用任何在线工具中的私钥解密加密的字符串。 有人可以帮助我。

我的公钥:

-----BEGIN PUBLIC KEY-----
MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgEac6cgM4Ch5vY2Rqvzw2ARaNEHv
PCbXWW1nPy3ft8CNFyLoIltwrnouY0azYECclONARh48qQUQ+UG62wNUtciLq9yX
3m0ePE7u/RYmNUnGWok6LMNZK1gGBu6TBnzNjDWi3CuR00xFzZ2TBtUMDowOa/+b
tfGTywGDLPJjgbtPAgMBAAE=
-----END PUBLIC KEY-----

我的私钥:

-----BEGIN RSA PRIVATE KEY-----
MIICWgIBAAKBgEac6cgM4Ch5vY2Rqvzw2ARaNEHvPCbXWW1nPy3ft8CNFyLoIltw
rnouY0azYECclONARh48qQUQ+UG62wNUtciLq9yX3m0ePE7u/RYmNUnGWok6LMNZ
K1gGBu6TBnzNjDWi3CuR00xFzZ2TBtUMDowOa/+btfGTywGDLPJjgbtPAgMBAAEC
gYAAxTd7ukA70NAzmjI+XjZNHdrSGVUTq2fLXMQAsR8lF6T3+YZebwVISfdFTzGu
osaxEANz0v+ZEY1WnT5EdAkjqwtYauj0tDnYmuciju2uVnEYLPOaOvpkmM7e9y+a
NWTvG/C0qAXtTT/EJgAwfCyrhuigyxzwUIyqhW2xgQ8MKQJBAIgM5xPKd30HU98t
jOHzouwSjsv5NIFOM9RnLPGA6HazQGu/0h2S27UnzaU8KKjln1X2q22GMa1cSvIL
q06e+MsCQQCE3oZudjOBgJaKtk7iETiIIoVVk3K1RMSGT/56SrglB1K1kNuFOpg+
obs+8j366gQk47ZgaIZwSRfro0VhTysNAkBiLEVWv6QHgZEhG6Jsrb1j8mQ+hd5A
bGj0HVuODYIxnVmgJvP8yStnhohbcpS4g7G9e1jqmIoiWdXu4ULFYeuPAkAIcKYz
cBi3ejaV2xzJqXRg2WiE1hfsQdEGAyDUHdjyqTNsyyXWobE4EUf2qKadQK5AtaJJ
H3qiuVHmqvlmRAQlAkB4Cl2nYBpK1IdusfwtjfaKppLa/r5k1D35cybxLn1uS3Xz
wwqRUuXrDkb4+TCD3B7Lkuym/kfFE2iIpANAVkeN
-----END RSA PRIVATE KEY-----

1 个答案:

答案 0 :(得分:0)

我遇到了同样的问题,并尝试了几天来弄清楚它是如何工作的,最后,我明白了!

您的私钥不是PKCS#8格式。

PKCS8键以

开头

----- BEGIN PRIVATE KEY -----

而不是

-----开始RSA私钥-----。

Java使用PKCS#8格式。

所以你有两种方法可以解决它:

<强>首先

Regenerate/convert你的服务器端/ PCKS#8格式的密钥,并在android应用程序中使用它

或第二:

在应用程序中转换您的私钥。 这样你需要包含third party library 到项目。

将此行添加到您的应用Gradle

compile 'com.madgag.spongycastle:core:1.56.0.0'

并将此getPrivateKey方法替换为:

`public static PrivateKey getPrivateKey(Context context) throws 
GeneralSecurityException, IOException {
        InputStream is = context.getResources().openRawResource(R.raw.rsa_2048_priv);
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        List<String> lines = new ArrayList<String>();
        String line = null;

            while ((line = br.readLine()) != null)
                lines.add(line);

            if (lines.size() > 1 && lines.get(0).startsWith("-----") && lines.get(lines.size() - 1).startsWith("-----")) {
                lines.remove(0);
                lines.remove(lines.size() - 1);
            }

            StringBuilder sb = new StringBuilder();
            for (String aLine : lines)
                sb.append(aLine);
            String keyString = sb.toString();

            byte[] encodedPrivateKey = Base64.decode(keyString, Base64.DEFAULT);

            try {
                ASN1Sequence primitive = (ASN1Sequence) ASN1Sequence
                        .fromByteArray(encodedPrivateKey);
                Enumeration<?> e = primitive.getObjects();
                BigInteger v = ((ASN1Integer) e.nextElement()).getValue();

                int version = v.intValue();
                if (version != 0 && version != 1) {
                    throw new IllegalArgumentException("wrong version for RSA private key");
                }
                /**
                 * In fact only modulus and private exponent are in use.
                 */
                BigInteger modulus = ((ASN1Integer) e.nextElement()).getValue();
                BigInteger publicExponent = ((ASN1Integer) e.nextElement()).getValue();
                BigInteger privateExponent = ((ASN1Integer) e.nextElement()).getValue();

                RSAPrivateKeySpec spec = new RSAPrivateKeySpec(modulus, privateExponent);
                KeyFactory kf = KeyFactory.getInstance("RSA");
                return kf.generatePrivate(spec);
            } catch (IOException e2) {
                throw new IllegalStateException();
            } catch (NoSuchAlgorithmException e) {
                throw new IllegalStateException(e);
            } catch (InvalidKeySpecException e) {
                throw new IllegalStateException(e);
            }

    }`

所以它会将私钥转换为PKCS#8, 并且您可以解码文本而不会出现 错误标记

的错误

希望有所帮助:)

这里是我找到解决方案的链接:

Getting RSA private key from PEM BASE64 Encoded private key file

JAVA RSA Decryption not working, throws InvalidKeySpecException

Convert PEM traditional private key to PKCS8 private key

How to include the Spongy Castle JAR in Android?