18

私は成功せずにそれをやろうとして数日経ちました。

ここStackOverflowには似たような質問がたくさんあり、そのうちの 2つでさえ私のものとまったく同じですが、未回答で未解決です。

私のシナリオ: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再び男)。

お世話になりました皆様、誠にありがとうございました。StackOverflow がすごい!

于 2012-07-18T12:30:53.780 に答える
3

重要なポイントがありません。公開キーと秘密キーは別々であり、一方を他方に基づいて計算することはできません。それが公開鍵暗号化のポイントの一種です。生のRSAの使用に関する問題はさておき、公開鍵で暗号化されたものがある場合は、それを復号化するために対応する秘密鍵が必要です。およびその逆。したがって、公開鍵ファイルがある場合は、そこからのみ公開鍵を取得できます。これは、データが対応する秘密鍵で暗号化されている場合にのみ役立ちます。

実際の例外として、開始と終了の「---」行を削除し、Base64.decode()を使用してバイト配列を取得し、これを使用してを作成しますX509EncodedKeySpec。これを行う1つの方法は、aのようなものを使用してBufferedReader行ごとに読み取り、「---」行を無視して、残りを1つの大きなに連結しStringます。

于 2012-07-18T01:58:31.627 に答える
1

指定したようなPEM形式からRSA公開鍵を生成するには(openssl gen。rsakey)

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

それで署名されたコンテンツを読むためにそれを使用しますか?

-ここで同様の質問で私の答えを見てください: https ://stackoverflow.com/a/12101100/546054

于 2012-08-23T23:12:55.047 に答える
1

公開鍵はデータの暗号化のみを行うことができます。公開鍵はデータを復号化できません。秘密鍵を使用してのみデータを復号化できます。要点は、公開鍵を誰にでも渡すことができ、秘密鍵の所有者だけが見ることができる暗号化されたメッセージを送信できることです。

暗号化技術の使用には細心の注意を払う必要があります。すべてのデバイスに秘密鍵を配布するだけでは、全員が同じ秘密鍵を持つことになり、セキュリティが低下するのではないかと心配しています。したがって、セキュリティをクラックしたい場合は、Google Play にアクセスしてアプリをダウンロードし、アプリから秘密鍵を引き出すだけです。ヴィオラ 全部見える。

なぜそれが機能しないのかという答えはわかりましたが、暗号化を使用している理由を知っていると、私が提供できない設計についてのアドバイスが必要です。何を隠しているのですか?

アップデート:

RSA がどのように機能するかのように、暗号化と署名の検証を実行しようとしているように聞こえますが、それが実際にどのように機能するか混乱しています。そのためには、秘密鍵と公開鍵の 2 つのセットが必要です。クライアント用の 1 セットのキーとサーバー用の 1 セットのキー。

Web サーバーはその公開鍵をクライアントに送信します。クライアントは、サーバーの公開鍵を使用して認証および暗号化されたメッセージをサーバーに送信し、クライアントの秘密鍵を使用してそのメッセージに署名することができます。サーバーの場合はその逆です。サーバーはクライアントの公開鍵を使用してメッセージを暗号化し、秘密鍵で署名してクライアントにメッセージを送信します。その後、クライアントはクライアントの秘密鍵でメッセージを復号化し、サーバーの公開鍵を使用して署名を検証できます。

今、SSL を再実装していますか? やめろ。SSL を使用します。

SSL が安全なチャネルを実現する方法は次のとおりです。クライアントは、Web サーバーから PUBLIC キーと、対称暗号化アルゴリズムの 1 つ以上の名前を受け取ります。共通のアルゴリズムを選択し、今後のすべてのメッセージに使用する秘密鍵を生成します。その秘密鍵を Web サーバーの公開鍵で暗号化し、選択したアルゴリズムとともに送信します。Web サーバーは、プライベート キーを使用して DECRYPTS を実行し、共有秘密キーを取得します。その後のすべての暗号化は、非対称暗号化よりもはるかに高速な共有秘密を使用した対称暗号化です。

于 2012-07-18T02:11:06.317 に答える