18

我已经尝试了几天但没有成功。

StackOverflow 中有很多类似的问题,甚至其中两个与我的完全相同,但未得到解答和解决:1)将 PHP RSA PublicKey 转换为 Android PublicKey 2)Android:如何使用 RSA 密钥解密 openssl 加密文件?

我的场景:我有一些使用 RSA 加密的文本(我没有加密)。我的 res/raw 文件夹中有一个“public.key”文件,其中包含解密它所需的公钥(与用于加密消息的私钥相关的公钥),其格式类似于以下示例: 在此处输入图像描述

我看到很多关于如何解密 RSA 文本的示例,如下所示:

public static byte[] decryptRSA( PublicKey key, byte[] text) throws Exception
      { 
          byte[] dectyptedText = null;

          Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
          cipher.init(Cipher.DECRYPT_MODE, key);
          dectyptedText = cipher.doFinal(text);
          return dectyptedText;
      }

但我的问题是,如何从文件中获取正确的 PublicKey 实例?没有这方面的例子。

如果我只是尝试:

    InputStream is = getResources().openRawResource(R.raw.public);
    DataInputStream dis = new DataInputStream(is);
    byte [] keyBytes = new byte [(int) is.available()];
    dis.readFully(keyBytes);
    dis.close();
    X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    return keyFactory.generatePublic(spec);

我在返回语句中得到一个 InvalidKeyException。我需要解码 Hex 或 Base64 吗?公钥文件的第一行和最后一行不是问题吗(带有“----BEGIN PUBLIC KEY----”的那些)?

也许我们可以在 StackOverflow 中第一次正确地得到这个答案:-)

4

4 回答 4

15

终于解决了!!!鼓,喇叭和迷人的交响乐!!!

public static byte[] decryptRSA(Context mContext, byte[] message) throws Exception { 

    // reads the public key stored in a file
    InputStream is = mContext.getResources().openRawResource(R.raw.sm_public);
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    List<String> lines = new ArrayList<String>();
    String line = null;
    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();
    Log.d("log", "keyString:"+keyString);

    // converts the String to a PublicKey instance
    byte[] keyBytes = Base64.decodeBase64(keyString.getBytes("utf-8"));
    X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey key = keyFactory.generatePublic(spec);

    // decrypts the message
    byte[] dectyptedText = null;
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, key);
    dectyptedText = cipher.doFinal(Base64.decodeBase64(message));
    return dectyptedText;
}

解决方案是对从文件中读取的公钥和加密消息本身进行 Base64 解码!

顺便说一句,我按照@Nikolay 建议的方式从文件中读取了公钥(tnx again man)。

非常感谢大家的帮助。StackOverflow 摇滚!

于 2012-07-18T12:30:53.780 回答
3

你错过了一个关键点——公钥和私钥是分开的,你不能根据另一个来计算一个。这就是公钥加密的意义所在。除了使用原始 RSA 的问题之外,如果您使用公钥加密了某些内容,则需要使用相应的私钥对其进行解密。反之亦然。因此,如果您有公钥文件,则只能从中获取公钥。仅当您的数据使用相应的私钥加密时才有用。

至于实际的例外:删除开头和结尾的“---”行,使用 Base64.decode() 获取字节数组,并使用它来创建您的X509EncodedKeySpec. 一种方法 - 使用类似 aBufferedReader逐行读取,忽略“---”行并将其余部分连接成一个大的String.

于 2012-07-18T01:58:31.627 回答
1

公钥只能加密数据。公钥不能解密数据。您只能使用私钥解密数据。关键是您可以将公钥分发给任何人和所有人,他们可以向您发送只有私钥持有者才能看到的加密消息。

您确实需要非常小心地使用加密技术。我担心您只是将私钥分发给您的所有设备,这会削弱您的安全性,因为每个人都将拥有相同的私钥。因此,如果我想破解您的安全性,我只需去 google play 并下载您的应用程序,然后将私钥从您的应用程序中提取出来。中提琴 我可以看到一切。

所以你有你的答案为什么它不起作用,但你现在需要关于设计的建议,我不能告诉你为什么要使用加密。你在隐藏什么?

更新:

听起来您正在尝试像 RSA 的工作方式一样执行加密和签名验证,但您对它的实际工作方式感到困惑。为此,您需要两组私钥/公钥。一组用于客户端的密钥和一组用于服务器的密钥。

Web 服务器会将其公钥发送给客户端。客户端可以使用服务器的公钥向服务器发送经过身份验证和加密的消息,然后使用客户端的私钥对该消息进行签名。服务器反之亦然。服务器将使用客户端的公钥加密消息并使用他的私钥对其进行签名以向客户端发送消息。然后客户端可以使用客户端的私钥解密消息并使用服务器的公钥验证签名。

现在您要重新实现 SSL 吗?停下来。使用 SSL。

以下是 SSL 如何实现安全通道。客户端从 Web 服务器接收 PUBLIC 密钥,以及对称加密算法的 1 个或多个名称。它选择一个他们共享的算法,然后生成一个用于所有消息的密钥。它使用 Web 服务器的公钥加密该密钥,并将其与它选择的算法一起发送。Web 服务器使用 PRIVATE 密钥解密以获取共享密钥。之后,所有加密都是使用共享密钥的对称加密,比非对称加密快得多。

于 2012-07-18T02:11:06.317 回答
1

从您提供的 PEM 格式生成 RSA 公钥(openssl gen.rsa key)

-----BEGIN PUBLIC KEY-----
SOMEDES3UNREADABLETEXT+PADDING==
-----END PUBLIC KEY

并用它来阅读一些用它签名的内容?

- 看看我在类似问题中的回答: https ://stackoverflow.com/a/12101100/546054

于 2012-08-23T23:12:55.047 回答