【问题标题】:RSA Decryption in Android using private Key使用私钥在 Android 中进行 RSA 解密
【发布时间】:2016-07-12 17:45:23
【问题描述】:

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

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

我附上我用过的代码sn-p:

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

【问题讨论】:

  • 您能否确保您不会无意中在您的密钥中添加换行符...在String keyString = sb.toString(); 之后请尝试:keyString = keyString.replaceAll("\\r|\\n", "");

标签: android encryption rsa private-key


【解决方案1】:

我也遇到了同样的问题,试了几天才搞明白,终于搞定了!

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

PKCS8 密钥以

开头

-----开始私钥-----

而不是

-----开始 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, 并且您可以解码您的文本而不会出现 wrong tag

的错误

希望对你有帮助:)

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

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?

【讨论】:

    猜你喜欢
    • 2012-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-27
    • 2015-12-19
    • 1970-01-01
    • 2012-05-07
    相关资源
    最近更新 更多