web-dev-qa-db-ja.com

Android=に公開鍵/秘密鍵を安全に生成して保存します

クライアントの公開鍵で暗号化されたデータを配布するWebアプリケーションを作成しています。現時点では、これは私が自分で配布する専用デバイスに対して機能しています。それらが出荷される前に、私は公開/秘密鍵ペアをデバイスのファームウェアにフラッシュします。

ただし、これは2017年なので、Androidアプリケーションを作成してAndroidデバイスを販売するデバイスの1つと同じように動作させるのは、簡単なので私が経験している唯一のボトルネックは、キーの配布です。

Androidデバイスでアプリを最初に起動したときに公開/秘密キーペアを生成し、それらを内部ストレージに安全に保存できますが、生成された公開キーを送信する方法を見つける必要がありますAndroidデバイスをサーバーに追加するため、サーバーはデータを暗号化できます。

公開鍵をHTTPリクエストとしてサーバーに送信できないのは、コンピューターを持っている人が公開鍵/秘密鍵のペアを生成して、サーバーにも送信して受信できないようにしたくないためです。データとして。 Androidアプリケーションを逆コンパイルするか、wiresharkを使用して、新しいキーの登録に使用されるURLを見つけるのは非常に簡単です。

この方法を使用する場合、リクエストが正当なAndroid=デバイスから発信されていることをサーバー側で確認するにはどうすればよいですか?

7
CryptoGuy51

制限状態とまったく同じように、そして this 回答のおかげで、正しい方法は次のようになります:

  1. 開発サーバーで暗号化するためのキーペアを生成する

    openssl genrsa -des3 -out private.pem 2048

    openssl rsa -in private.pem -outform PEM -pubout -out public.pem

  2. 公開鍵はアプリケーションコードに格納します。場所は関係ありません。これは、手順5の関数で使用されます。暗号化メカニズムの変更を防ぐために、コードを難読化する可能性があります。 (暗号化は、げっぷプロキシのようなもので転送中の改ざんを防ぐだけです。smaliスキルは誰か?)

  3. デバイスでキーペアを生成します(これはダウンしたと述べましたが、誰かが不思議に思った場合に備えて)

    public static KeyPair getKeyPair() {
    KeyPair kp = null;
    try {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(2048);
        kp = kpg.generateKeyPair();
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    return kp; 
    }
    
  4. 公開鍵を分離して、必要な場所に保管します。秘密鍵をセキュアストアに保存します。

    KeyPair clientKeys = getKeyPair();
    publicKey = clientKeys.getPublic();
    
  5. 組み込みのdev公開鍵でクライアントの公開鍵を暗号化して、自宅に送信できるようにします。

    public static String encryptToRSAString(String clearText, String publicKey) {
        String encryptedBase64 = "";
        try {
            KeyFactory keyFac = KeyFactory.getInstance("RSA");
            KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKey.trim().getBytes(), Base64.DEFAULT));
            Key key = keyFac.generatePublic(keySpec);
            // get an RSA cipher object and print the provider
            final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
            // encrypt the plain text using the public key
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] encryptedBytes = cipher.doFinal(clearText.getBytes("UTF-8"));
            encryptedBase64 = new String(Base64.encode(encryptedBytes, Base64.DEFAULT));
        } catch (Exception e) {
            e.printStackTrace();
        }
            return encryptedBase64.replaceAll("(\\r|\\n)", "");
    }
    
5
J.A.K.

登録ユーザーからのみキーを受け取りたいのでしょうか?認証には、最終的に、サーバーと登録ユーザーとの間の共有秘密が必要です。この秘密により、EKEや類似のプロトコルなど、鍵交換の適切なプロトコルを使用して鍵を交換することができます。 https://en.wikipedia.org/wiki/Encrypted_key_exchange

しかし、サーバーのSSL証明書を持っている場合(私はあなたが持っていると思います)、登録ユーザーとの接続を確立すると、暗号化された接続であるため、彼はこのチャネルでパブリックペアを送信できます。また、独自のプロトコルまたは既知のプロトコルを開発/実装しないことをお勧めします。そのため、このオプションの方が適しています。

サーバーのSSL証明書とは、信頼できるCA機関によって署名された証明書を意味します

0
stackoverflower