web-dev-qa-db-fra.com

Générez et stockez en toute sécurité des clés publiques / privées sur Android

Je fais une application web qui distribue des données cryptées avec les clés publiques de ses clients. En ce moment, cela fonctionne pour les appareils dédiés que je distribue moi-même. Avant leur expédition, je flashe la paire de clés publique/privée dans le firmware des appareils.

Cependant, comme nous sommes en 2017, je voulais également créer une application Android pour que tout appareil Android agisse comme l'un des appareils que je vends, car c'est plus facile). pour les clients. Le seul goulot d'étranglement que je connais est la distribution des clés.

Je peux générer une paire de clés publique/privée sur l'appareil Android lors du premier démarrage de l'application et les stocker en toute sécurité dans le stockage interne, mais je dois trouver un moyen d'envoyer la clé publique générée de l'appareil Android sur mon serveur, afin que mon serveur puisse crypter les données avec.

La raison pour laquelle je ne peux pas simplement envoyer la clé publique en tant que demande HTTP à mon serveur est que je ne veux pas qu'une personne avec un ordinateur puisse générer une paire de clés publique/privée et l'envoyer à mon serveur pour pouvoir également recevoir données comme. Il est très facile de décompiler les applications Android ou d'utiliser wirehark pour connaître l'url utilisée pour enregistrer les nouvelles clés.

Si je devais utiliser cette méthode, comment pourrais-je vérifier à la fin de mes serveurs que la demande provient d'un appareil légitime Android?

7
CryptoGuy51

Exactement comme le dit Limit, et grâce à la réponse this , la bonne façon serait de:

  1. Générez une paire de clés pour le chiffrement sur votre serveur de développement

    openssl genrsa -des3 -out private.pem 2048

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

  2. Stockez la clé publique dans le code de l'application, peu importe où. Cela sera utilisé dans la fonction à l'étape 5. Peut-être obscurcir le code pour empêcher la modification du mécanisme de cryptage. (le cryptage empêchera uniquement la falsification en transit avec quelque chose comme un proxy burp.

  3. Générez une paire de clés sur l'appareil (vous avez mentionné que vous aviez ce problème, mais juste au cas où quelqu'un se demanderait)

    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. Isolez les clés publiques et stockez-les où vous le souhaitez. Stockez la clé privée dans le magasin sécurisé.

    KeyPair clientKeys = getKeyPair();
    publicKey = clientKeys.getPublic();
    
  5. Chiffrez la clé publique du client avec la clé publique de développement intégrée pour pouvoir la renvoyer à la maison.

    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.

Vous souhaitez peut-être recevoir les clés uniquement des utilisateurs enregistrés? L'authentification nécessitera finalement un secret partagé entre votre serveur et l'utilisateur enregistré. Avec ce secret, vous pouvez essayer d'échanger des clés en utilisant un bon protocole d'échange de clés, par exemple, EKE ou un protocole similaire. https://en.wikipedia.org/wiki/Encrypted_key_exchange

Mais, si vous avez un certificat SSL du serveur (et je suppose que vous l'avez), lorsque vous établissez une connexion avec un utilisateur enregistré, il peut vous envoyer sa paire publique sur ce canal, car c'est déjà une connexion cryptée. Également considéré comme une meilleure pratique pour ne pas développer/implémenter vos propres protocoles de sécurité ou même connus, cette option est probablement meilleure.

Par sertificate SSL du serveur, je veux dire sertificate signé par une autorité de certification de confiance

0
stackoverflower