Как сохранить и получить открытый ключ RSA в хранилище ключей Android, который создается серверным приложением?

Приложение на стороне сервера генерирует пару ключей RSA, и как часть процесса обмена ключами я получаю этот открытый ключ с сервера, и теперь я хочу сохранить этот ключ в Android KeyStore. Я видел примеры с созданием пары ключей RSA с помощью KeyGenerator и сохранением их в android KeyStore, но я понятия не имею, как хранить уже сгенерированный открытый ключ RSA. Любая помощь будет высоко оценен.

7
0
4 263
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не уверен, что вас смущает или чего именно вы пытаетесь достичь. KeyStore может содержать только три типа записей: симметричные ключи, частные ключи и сертификаты. Следовательно, если вы хотите сохранить открытый ключ, он должен быть отформатирован в сертификат. Вам решать, использует ли ваше приложение какие-либо другие функции сертификатов X509.

Также неясно, хотите ли вы использовать какое-либо старое хранилище ключей на Android или тоAndroidKeyStore. Последний предлагает расширенные функции, но нужны они вам или нет, зависит от вашей модели угрозы. В любом случае, вот пример, который показывает, как импортировать открытый ключ Google в хранилище ключей Android, как установить на нем некоторые свойства и как использовать его для шифрования ключа AES.

import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.util.Base64;
import android.util.Log;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;

public class MainActivity extends AppCompatActivity {

    private static final String THE_CERT = "-----BEGIN CERTIFICATE-----\n" +
            "MIIIPjCCByagAwIBAgIIWcyJ5Cnzp3UwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UE\n" +
            "BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl\n" +
            "cm5ldCBBdXRob3JpdHkgRzIwHhcNMTgwMzEzMTgzMDQ1WhcNMTgwNjA1MTgxNjAw\n" +
            "WjBmMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN\n" +
            "TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEVMBMGA1UEAwwMKi5n\n" +
            "b29nbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtXqeeS6r\n" +
            "sLfE5dx5asD7dngw0Dev9rhgDYM9kAuV9VxbZJ2ehZM4Nk1zGGSlqidgRWsVSNrx\n" +
            "qb513IyrtxDSvTTGh8ihFGNTL/H61e+cYU565RCw4siOU0IevyhynPVh8D38pe5U\n" +
            "bkGDmkiP7tOVozQE+3Q7l6xaIvlq9hIAb0aTWdJ6AOm3r/iMRdiUv/kxIienQ4v/\n" +
            "RY/h3K/llz1E+S+TAyM2+As8o2nRMGrp9/hg8zIs3CLLv2km9VS/fgTQrM5pcfDf\n" +
            "iX6Tgzb+6RSGHnT7GgNA3R1LXo96gnwf3zlX3SqpvV8pQf2Y3TxhLRB7J28yZFef\n" +
            "P6d9t2EqlHZv+wIDAQABo4IFCzCCBQcwEwYDVR0lBAwwCgYIKwYBBQUHAwEwggPh\n" +
            "BgNVHREEggPYMIID1IIMKi5nb29nbGUuY29tgg0qLmFuZHJvaWQuY29tghYqLmFw\n" +
            "cGVuZ2luZS5nb29nbGUuY29tghIqLmNsb3VkLmdvb2dsZS5jb22CFCouZGI4MzM5\n" +
            "NTMuZ29vZ2xlLmNuggYqLmcuY2+CDiouZ2NwLmd2dDIuY29tghYqLmdvb2dsZS1h\n" +
            "bmFseXRpY3MuY29tggsqLmdvb2dsZS5jYYILKi5nb29nbGUuY2yCDiouZ29vZ2xl\n" +
            "LmNvLmlugg4qLmdvb2dsZS5jby5qcIIOKi5nb29nbGUuY28udWuCDyouZ29vZ2xl\n" +
            "LmNvbS5hcoIPKi5nb29nbGUuY29tLmF1gg8qLmdvb2dsZS5jb20uYnKCDyouZ29v\n" +
            "Z2xlLmNvbS5jb4IPKi5nb29nbGUuY29tLm14gg8qLmdvb2dsZS5jb20udHKCDyou\n" +
            "Z29vZ2xlLmNvbS52boILKi5nb29nbGUuZGWCCyouZ29vZ2xlLmVzggsqLmdvb2ds\n" +
            "ZS5mcoILKi5nb29nbGUuaHWCCyouZ29vZ2xlLml0ggsqLmdvb2dsZS5ubIILKi5n\n" +
            "b29nbGUucGyCCyouZ29vZ2xlLnB0ghIqLmdvb2dsZWFkYXBpcy5jb22CDyouZ29v\n" +
            "Z2xlYXBpcy5jboIUKi5nb29nbGVjb21tZXJjZS5jb22CESouZ29vZ2xldmlkZW8u\n" +
            "Y29tggwqLmdzdGF0aWMuY26CDSouZ3N0YXRpYy5jb22CCiouZ3Z0MS5jb22CCiou\n" +
            "Z3Z0Mi5jb22CFCoubWV0cmljLmdzdGF0aWMuY29tggwqLnVyY2hpbi5jb22CECou\n" +
            "dXJsLmdvb2dsZS5jb22CFioueW91dHViZS1ub2Nvb2tpZS5jb22CDSoueW91dHVi\n" +
            "ZS5jb22CFioueW91dHViZWVkdWNhdGlvbi5jb22CByoueXQuYmWCCyoueXRpbWcu\n" +
            "Y29tghphbmRyb2lkLmNsaWVudHMuZ29vZ2xlLmNvbYILYW5kcm9pZC5jb22CG2Rl\n" +
            "dmVsb3Blci5hbmRyb2lkLmdvb2dsZS5jboIcZGV2ZWxvcGVycy5hbmRyb2lkLmdv\n" +
            "b2dsZS5jboIEZy5jb4IGZ29vLmdsghRnb29nbGUtYW5hbHl0aWNzLmNvbYIKZ29v\n" +
            "Z2xlLmNvbYISZ29vZ2xlY29tbWVyY2UuY29tghhzb3VyY2UuYW5kcm9pZC5nb29n\n" +
            "bGUuY26CCnVyY2hpbi5jb22CCnd3dy5nb28uZ2yCCHlvdXR1LmJlggt5b3V0dWJl\n" +
            "LmNvbYIUeW91dHViZWVkdWNhdGlvbi5jb22CBXl0LmJlMGgGCCsGAQUFBwEBBFww\n" +
            "WjArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcyLmNydDAr\n" +
            "BggrBgEFBQcwAYYfaHR0cDovL2NsaWVudHMxLmdvb2dsZS5jb20vb2NzcDAdBgNV\n" +
            "HQ4EFgQU2Xh9D7F5dJYCBqsWcKChI16NReswDAYDVR0TAQH/BAIwADAfBgNVHSME\n" +
            "GDAWgBRK3QYWG7z2aLV29YG2u2IaulqBLzAhBgNVHSAEGjAYMAwGCisGAQQB1nkC\n" +
            "BQEwCAYGZ4EMAQICMDAGA1UdHwQpMCcwJaAjoCGGH2h0dHA6Ly9wa2kuZ29vZ2xl\n" +
            "LmNvbS9HSUFHMi5jcmwwDQYJKoZIhvcNAQELBQADggEBAFxBsH2U6j4KzZbNcyN1\n" +
            "UGiJnMn64DIXH8wsWrFEGAq3ONRhPgKd3AnbaBUdNdrRgOhfA3RtLvvnxsKn0rX6\n" +
            "Oz8+p5DZxJooUgWlet9NounLDe5um6m5NqLIGefdI49Ukn6IwBtCO5DD7rZTygTa\n" +
            "B499H9N0ixI9wGBdlZ37tOpCxayNb08eizU1uQEhb1/oxnXf0e6trPfC8krDL0Ks\n" +
            "Pyf3JgB5oBTiNAfix2zme1FrpXcKehOj2urnLQRr5EpminCJ+0uHI1sqiJbcSHrU\n" +
            "6TPQcOzZ7/haw1yY2bpy+sB4oXUMaNJxh6e2AiCeVf4MtX9EsYEnhsfc2XS50J32\n" +
            "nKo=\n" +
            "-----END CERTIFICATE-----";

    private void doExample() {
        try {
            X509Certificate googleCert = (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(new ByteArrayInputStream(THE_CERT.getBytes(StandardCharsets.UTF_8)));
            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            KeyProtection keyProtection = new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_VERIFY)
                    .setDigests(KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_SHA256)
                    .setRandomizedEncryptionRequired(true)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
                    .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS)
                    .setUserAuthenticationRequired(false)
                    .build();
            keyStore.load(null);
            keyStore.setEntry("googlecert", new KeyStore.TrustedCertificateEntry(googleCert), keyProtection);
            // Now use the entry
            KeyGenerator aesKeygen = KeyGenerator.getInstance("AES");
            aesKeygen.init(128);
            Key aesKey = aesKeygen.generateKey();
            // Wrap key for transport
            KeyStore keyStore2 = KeyStore.getInstance("AndroidKeyStore");
            keyStore2.load(null);
            Certificate googleCert2 = keyStore2.getCertificate("googlecert");
            Cipher rsaCipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding");
            rsaCipher.init(Cipher.WRAP_MODE, googleCert2);
            byte[] rsaEncrypted = rsaCipher.wrap(aesKey);
            Log.d("crypt", Base64.encodeToString(rsaEncrypted, Base64.DEFAULT));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Я пытался хранить открытый ключ в AndroidKeyStore, как будто мы храним симметричный ключ. Теперь я понял, что его нужно отформатировать в сертификат, чтобы хранить в AndroidKeyStore.

Raneez Ahmed 31.03.2018 11:29

Один вопрос, поскольку хакер ничего не может сделать с открытым ключом, можно ли сохранить его в SharedPreference или встроить в строковую константу?

Raneez Ahmed 31.03.2018 11:31

Да, хранить можно практически любым способом. Это не обязательно должно быть секретом, но это не должно быть изменено хакером.

President James K. Polk 31.03.2018 14:09

Другие вопросы по теме