android 如何安全地保存密钥库

nfs0ujit  于 2023-05-27  发布在  Android
关注(0)|答案(3)|浏览(278)

我已经写了一个API,以便我的不同应用程序可以使用它。它只是检查应用程序是否在服务器上注册。如果没有,那么它会生成公钥/私钥对,并通过发送CSR到我的服务器获得签名证书。下一次使用签名的证书和私钥时。最初,我有原始的默认密钥库文件(B/c),我所有的通信都是通过SSL,即最初使用默认密钥库,在注册到用户生成的密钥库之后)
我的API工作正常。我遇到的问题与我缺乏知识或错误的方法有关,因此我需要帮助。
我正在使用以下类保存/检索我的密钥对

public class KeyIOHandler {

    public static void writePublicKeyToPreferences(KeyPair key, Context context) {
        StringWriter publicStringWriter = new StringWriter();
        try {
            PemWriter pemWriter = new PemWriter(publicStringWriter);
            pemWriter.writeObject(new PemObject("myapp.PUBLIC KEY", key.getPublic().getEncoded()));
            pemWriter.flush();
            pemWriter.close();
            SharedPreferences preferences = context.getSharedPreferences("SHARED_PREFERENCES",0);
            preferences.edit().putString("RSA_PUBLIC_KEY", publicStringWriter.toString()).commit();
            Log.e("Public  Key", publicStringWriter.toString());
        } catch (IOException e) {
            Log.e("RSA", e.getMessage());
            e.printStackTrace();
        }
    }

    public static void writePrivateKeyToPreferences(KeyPair keyPair, Context context) {
        StringWriter privateStringWriter = new StringWriter();
        try {
            PemWriter pemWriter = new PemWriter(privateStringWriter);
            pemWriter.writeObject(new PemObject("myapp.PRIVATE KEY", keyPair.getPrivate().getEncoded()));
            pemWriter.flush();
            pemWriter.close();
            SharedPreferences preferences = context.getSharedPreferences("SHARED_PREFERENCES",0);
            preferences.edit().putString("RSA_PRIVATE_KEY", privateStringWriter.toString()).commit();
            Log.e("Private Key",privateStringWriter.toString());
        } catch (IOException e) {
            Log.e("RSA", e.getMessage());
            e.printStackTrace();
        }
    }

    public static PublicKey getRSAPublicKeyFromString(String publicKeyPEM) throws Exception {
        publicKeyPEM = stripPublicKeyHeaders(publicKeyPEM);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA", "SC");
        byte[] publicKeyBytes = Base64.decode(publicKeyPEM.getBytes("UTF-8"));
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes);
        return keyFactory.generatePublic(x509KeySpec);
    }

    public static PrivateKey getRSAPrivateKeyFromString(String privateKeyPEM) throws Exception {
        privateKeyPEM = stripPrivateKeyHeaders(privateKeyPEM);
        KeyFactory fact = KeyFactory.getInstance("RSA", "SC");
        byte[] clear = Base64.decode(privateKeyPEM);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear);
        PrivateKey priv = fact.generatePrivate(keySpec);
        Arrays.fill(clear, (byte) 0);
        return priv;
    }

    public static String stripPublicKeyHeaders(String key) {
        //strip the headers from the key string
        StringBuilder strippedKey = new StringBuilder();
        String lines[] = key.split("\n");
        for (String line : lines) {
            if (!line.contains("BEGIN PUBLIC KEY") && !line.contains("END PUBLIC KEY") && !isNullOrEmpty(line.trim())) {
                strippedKey.append(line.trim());
            }
        }
        return strippedKey.toString().trim();
    }

    public static String stripPrivateKeyHeaders(String key) {
        StringBuilder strippedKey = new StringBuilder();
        String lines[] = key.split("\n");
        for (String line : lines) {
            if (!line.contains("BEGIN PRIVATE KEY") && !line.contains("END PRIVATE KEY") && !isNullOrEmpty(line.trim())) {
                strippedKey.append(line.trim());
            }
        }
        return strippedKey.toString().trim();
    }

    public static boolean isNullOrEmpty(String str) {
        return str == null || str.isEmpty();
    }
}

通过使用下面的方法,我正在生成我的密钥库,但我很困惑如何以及在哪里可以安全地存储这个密钥库,以便我可以在应用程序的剩余生命中使用它。在共享首选项中,我不能存储任何对象,所以在哪里保存这个密钥库。现在我在我的类中有静态密钥库对象。(这是我知道的最糟糕的,但只是为了使它工作,我使它静态)

private boolean  addToStore(){
        try {
            Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
            clientPkcs12 = KeyStore.getInstance("PKCS12");
            clientPkcs12.load(null, null);
            clientPkcs12.setKeyEntry("clientCert", keyPair.getPrivate(), "123456".toCharArray(), chain);
        }
        catch(Exception ex){
            Log.e("",ex.getCause().getMessage());
        }
        return false;
    }

我已经通过几个职位,其中这是值得注意的一个nelenkov.blogspot,但没有得到我如何才能实现我的目标,或者我错了保存密钥库?我的意思是我每次都要创建密钥库吗?

ldfqzlk8

ldfqzlk81#

我不知道你为什么要把你的凭证保存在共享首选项中,当你有Keystore的时候。一旦你将你的密钥库文件加载到内存中,你就可以随时添加/检索密钥。当你完成后,只需调用以下命令将其保存在文件中:

FileOutputStream out = new FileOutputStream(keystoreFile);
    keystore.store(out, password);
    out.close();

从文件加载:

keystore.load(new FileInputStream(keystoreFile, password);

@回复评论
您应该只使用Keystore。来自共享首选项的数据不受保护,并且很容易从中检索私钥。您没有使用任何类型的加密,因此您的密钥存储在纯PEM文本中。但是如果你使用Keystore,你的密钥是受密码保护的(在密钥级别和密钥库级别),所以如果任何人在没有密码的情况下获得Keystore文件,他将很难破解它。保存Keystore文件的最佳位置是您的应用程序内部空间磁盘,没有root手机无法访问(创建文件时为Context.MODE_PRIVATE)。

ccrfmcuu

ccrfmcuu2#

你已经回答了你自己的问题。将它们保存在KeyStore中,* 而不是 * 在首选项文件中。

cgyqldqp

cgyqldqp3#

除非重新创建,否则KeyStore会自行保存。即使在重新启动应用程序后,我们也可以使用getKeys()从密钥存储库中提取密钥。为此,首先检查privateKeysecretKey中的任何一个是否已经存在。如果存在,请不要重新创建KeyPair(这会直接创建一个新的KeyStore)。注意:我实现keyStore的方式在卸载应用后会被删除。

public KeyStore createKeyStore(){
        try {
            KeyStore ks = KeyStore.getInstance(ANDROID_KEYSTORE);
            ks.load(null);
            return ks;
        }
        catch (KeyStoreException e){}
        return  null;
    }

public KeyPair getAsymmetricKeyPair() throws NoSuchPaddingException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException {
             KeyStore ks=createKeyStore();
             KeyPair keyPair;
             try {
                  PrivateKey privateKey= (PrivateKey) ks.getKey(KEY_ALIAS, null);
                 //privateKey is null it means that there is no keyStore Available   
                  if(privateKey==null){
       
                  //Creating a new KeyStore while creating a KeyPair using keyPairGenerator
                     keyPair=this.createAsymmetricKeyPair();
                     return keyPair;
                  }
                  else //When the keyStore is already available
                  {
                      PublicKey publicKey=(PublicKey) ks.getCertificate(KEY_ALIAS).getPublicKey();
                 //Creating a KeyPair After retrieving them from KeyStore
                      return new KeyPair(publicKey,privateKey);
                  }
             }
             catch (UnrecoverableEntryException e){}
        return null;
    }
 public KeyPair createAsymmetricKeyPair(){
    try {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
                KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEYSTORE);

        keyPairGenerator.initialize(
                new KeyGenParameterSpec.Builder(
                        KEY_ALIAS,
                        KeyProperties.PURPOSE_DECRYPT|KeyProperties.PURPOSE_ENCRYPT)
                        .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                        .setBlockModes(KeyProperties.BLOCK_MODE_ECB)
                        .build());
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        return keyPair;
    }
    catch(Exception e){}
    return null;
}

相关问题