存储RSA私钥Android

问题描述 投票:20回答:4

在创建用于加密/解密消息并通过Internet发送消息的简单消息传递android应用程序的过程中,我决定使用RSA公钥/私钥加密。问题是如何存储私钥,以便即使手机被恶意扎根,密钥也将保持安全?据我了解,KeyStore用于证书,不能用于此吗?我应该使用AES将私钥加密为文本文件吗?我在安全方面的经验很少,因此,请随时纠正我的想法,并提出您的意见!

亲切的问候。

android encryption storage private-key
4个回答
8
投票

我认为KeyStore可能适合您使用。它能够存储RSA密钥并使用AES对其进行加密,因此,即使具有root用户访问权限,也必须在没有密码或暴力破解的情况下才能提取它们。

这里有一篇有关使用KeyStore的好文章:http://nelenkov.blogspot.fr/2012/05/storing-application-secrets-in-androids.html


4
投票

您可以使用Android上的SharedPreference保留RSA公钥/私钥。为了在手机被恶意扎根时保护您的钥匙安全,您可以执行以下步骤:

1:要加密任何数据时,请生成密钥对。2:提示用户输入密码。3:使用该密码生成对称密钥以加密您的私钥。4:您可以使用公钥加密数据,也可以使用私钥解密。5:您可以保留一个会话,以获取在步骤2中提示的密码。在该会话期间,您可以使用对称密钥(从密码生成)来加密/解密私钥。

以下代码段显示了如何存储和获取公共密钥

public void setPublicKey(PublicKey publicKey, String key, Context context) {

    byte[] pubKey = publicKey.getEncoded();
    String pubKeyString = Base64.encodeBytes(pubKey);
    this.setString(key, pubKeyString, context);
}

public PublicKey getPublicKey(String key,Context context) {

    PublicKey pKey = null;
    try {

        String pubString = this.getString(key, context);

        if(pubString!=null) {
            byte[] binCpk = Base64.decode(pubString);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(binCpk);
            pKey = keyFactory.generatePublic(publicKeySpec);
        }
        }catch(Exception e){
    }
    return pKey;
}

下面的代码片段显示了如何存储和获取私钥。

public void setPrivateKey(PrivateKey privateKey, String key, Context context) {

    byte[] priKey = privateKey.getEncoded();
    String priKeyString = Base64.encodeBytes(priKey);
    this.setString(key, priKeyString, context);
}

public PrivateKey getPrivateKey(String key, Context context) {

    PrivateKey privateKey = null;

    try {
        String privateString = this.getString(key, context);
        if(privateString!=null){
            byte[] binCpk = Base64.decode(privateString);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(binCpk);
            privateKey = keyFactory.generatePrivate(privateKeySpec);
        }
    } 
    catch(Exception e){
    }
    return privateKey;
}

2
投票

文件系统中的任何密钥库(P12,JKS,AKS)都不能足够安全地保存RSA私钥。只有SmartCard或安全令牌才能提供高级安全性。阅读本书:“ Android安全内部知识”。在本书中,您会找到有关Android安全性和JCA提供程序的良好描述。


0
投票

是,您可以使用KeyStore将RSA私钥保留在Android Studio中,并根据需要进行检索以进行签名。基本思想是在生成密钥时,将“ AndroidKeystore”用作提供程序。这个人:https://stackoverflow.com/questions/49410575/keystore-operation-failed-with-rsa-sign-and-verify#=的重点是确保设置签名填充。这对我有用,如下所示:

public void storeKeyAsymmetric(){    //Generate the keys (public and private together) using KeyStore
KeyPairGenerator kpGenerator = null;
    try {
        kpGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    catch (NoSuchProviderException e) {
        e.printStackTrace();
    }
    try {
        kpGenerator.initialize(new KeyGenParameterSpec.Builder("aliasOfYourChoice", KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
                .setDigests(KeyProperties.DIGEST_SHA512, KeyProperties.DIGEST_SHA256)
                .setKeySize(2048)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1, KeyProperties.ENCRYPTION_PADDING_RSA_OAEP, KeyProperties.ENCRYPTION_PADDING_NONE)
                .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1, KeyProperties.SIGNATURE_PADDING_RSA_PSS)
                .build());
        keyPairAsymmetric = kpGenerator.generateKeyPair();
        devicePublic = keyPairAsymmetric.getPublic();
        byte[] encoding = devicePublic.getEncoded();
        strDevicePublicPEM = Crypto.writePEM(encoding);
    } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }
}

稍后,您可以使用该私钥对消息进行签名,如下所示:

public static String verifiedDeviceSignature(String dataToSign){
    boolean verified = false;
    String signature = null;
    MessageDigest digest = null;
    try {
        digest = MessageDigest.getInstance("SHA-512");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    digest.update(dataToSign.getBytes(StandardCharsets.UTF_8));
    byte[] hash = digest.digest();

    try {
        KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
        ks.load(null);
        //******This is a PrivateKeyEntry
        KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry("aliasOfYourChoice", null);  //null if you don't have key locked up with password
        PrivateKey privateKey = privateKeyEntry.getPrivateKey();
        Signature s = Signature.getInstance("SHA512withRSA");
        s.initSign(privateKey);
        s.update(dataToSign.getBytes(StandardCharsets.UTF_8));  //TODO:  Change this to hash
        byte[] sig = s.sign();

        PublicKey publicKey = ks.getCertificate("aliasOfYourChoice").getPublicKey();

        Signature v = Signature.getInstance("SHA512withRSA");
        v.initVerify(publicKey);
        v.update(dataToSign.getBytes(StandardCharsets.UTF_8));  //TODO:  Change this to hash
        verified = v.verify(sig);
        String strSig = new String(Base64.encode(sig, 2));
        signature = strSig;
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (UnrecoverableEntryException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (SignatureException e) {
        e.printStackTrace();
    }

    if(verified){
        Log.d("***verifiedDeviceSignature*: ", "Signature Verified");
        //TODO:  URL encode
        return signature;
    }else {
        return "Not verified.";
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.