Android - 编码&用私钥解码RSA? [英] Android - Encode & Decode RSA with Private Key?

查看:249
本文介绍了Android - 编码&用私钥解码RSA?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Android 4.3中引入的Android Key Store Provider生成和存储的私钥对Android上的Strings进行编码和解码。



我可以成功使用以下代码生成并获取私钥:

  private void generatePrivateKey(Activity context,String alias){
/ **使用* KeyPairGenerator API在KeyStore中生成新条目。我们必须在这里指定一个*自签名X.509证书的属性,这样KeyStore可以将公钥部分附加到它。如果需要,可以用证书颁发机构(CA)签发的*证书替换。 * /

日历cal = Calendar.getInstance();
Date now = cal.getTime();
cal.add(Calendar.YEAR,1);
日期结束= cal.getTime();

KeyPairGenerator kpg = null;
try {
kpg = KeyPairGenerator.getInstance(RSA,AndroidKeyStore);
} catch(NoSuchAlgorithmException e){
e.printStackTrace();
} catch(NoSuchProviderException e){
e.printStackTrace();
}
try {
kpg.initialize(new KeyPairGeneratorSpec.Builder(context)
.setAlias(alias)
.setStartDate(now)
.setEndDate (end)
.setSerialNumber(BigInteger.valueOf(1))
.setSubject(new X500Principal(CN =+ alias))
.build());
} catch(InvalidAlgorithmParameterException e){
e.printStackTrace();
}

KeyPair kp = kpg.generateKeyPair();

/ *
*使用
*AndroidKeyStore提供程序加载Android KeyStore实例,列出目前存储的
*条目。
* /
KeyStore ks = null;
try {
ks = KeyStore.getInstance(AndroidKeyStore);
ks.load(null);
枚举< String> aliases = ks.aliases();
} catch(KeyStoreException e){
e.printStackTrace();
} catch(CertificateException e){
e.printStackTrace();
} catch(NoSuchAlgorithmException e){
e.printStackTrace();
} catch(IOException e){
e.printStackTrace();
}

/ *
*在KeyStore中使用PrivateKey创建一个超过
*的一些数据的签名。
* /

KeyStore.Entry entry = null;
try {
entry = ks.getEntry(alias,null);
} catch(NoSuchAlgorithmException e){
e.printStackTrace();
} catch(UnrecoverableEntryException e){
e.printStackTrace();
} catch(KeyStoreException e){
e.printStackTrace();
}
if(!(Entry instanceof KeyStore.PrivateKeyEntry)){
Log.w(E,不是PrivateKeyEntry的一个实例);
}
else {
Log.w(E,Got Key!);
privateKeyEntry =((KeyStore.PrivateKeyEntry)条目).getPrivateKey();
}

}

这里是我的代码用于加密(编码)和解密(解码):

  private String encryptString(String value){
byte [ ] encodedBytes = null;
尝试{
密码密码= Cipher.getInstance(RSA / ECB / PKCS1Padding,AndroidOpenSSL);
cipher.init(Cipher.ENCRYPT_MODE,privateKeyEntry);
encodedBytes = cipher.doFinal(value.getBytes());
} catch(Exception e){
e.printStackTrace();
}

返回Base64.encodeToString(encodedBytes,Base64.DEFAULT);
}

private String decryptString(String value){
byte [] decodedBytes = null;
try {
Cipher c = Cipher.getInstance(RSA / ECB / PKCS1Padding,AndroidOpenSSL);
c.init(Cipher.DECRYPT_MODE,privateKeyEntry);
decodedBytes = c.doFinal(Base64.decode(value,Base64.DEFAULT));
} catch(Exception e){
e.printStackTrace();
}

return new String(decodedBytes);
}

加密似乎工作正常,但是当我尝试解密时,我得到以下错误:

  javax.crypto.BadPaddingException:error:0407106B:rsa例程:RSA_padding_check_PKCS1_type_2:块类型不是02 

Googling这似乎暗示用于解密的私钥与用于解密的私钥不同,但在我的代码我使用完全相同的私钥两者。我也看到它建议手动设置密钥大小,但在KeyPairGenerator构建器中这样做:

  .setKeySize(1024 ); 

没有工作,似乎只能用于API 19,我需要定位API 18.



任何人都可以帮助我指出解决方案的正确方向?

解决方案

您是使用公开密钥进行加密。 / p>

当您使用非对称加密算法时,您需要使用 公开加密 em>您的数据,然后再将 私人密钥 解密。



除了加密之外,您还可以使用私钥进行签名,但这不是您想要的,所以现在就忘记一下。



如果您从生成的对中获取公钥,加密字符串和解密时的私钥,则应该获得所需的结果。您可以通过从包含您的私钥的密钥库对象访问 证书 来提取公钥。



或者,您也可以使用像AES这样的对称算法,这样使您的工作变得更容易。此外,对称算法通常要快得多,这就是为什么不使用非对称算法,而是结合对称算法,构建所谓的混合算法。


I am trying to encode and decode Strings on Android using a Private Key generated and stored using the Android Key Store Provider that was introduced in Android 4.3

I can successfully generate and get the private key using the following code:

 private void generatePrivateKey(Activity context, String alias){
    /** Generate a new entry in the KeyStore by using the  * KeyPairGenerator API. We have to specify the attributes for a  * self-signed X.509 certificate here so the KeyStore can attach  * the public key part to it. It can be replaced later with a  * certificate signed by a Certificate Authority (CA) if needed.  */

    Calendar cal = Calendar.getInstance();
    Date now = cal.getTime();
    cal.add(Calendar.YEAR, 1);
    Date end = cal.getTime();

    KeyPairGenerator kpg = null;
    try {
        kpg = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (NoSuchProviderException e) {
        e.printStackTrace();
    }
    try {
        kpg.initialize(new KeyPairGeneratorSpec.Builder(context)
                .setAlias(alias)
                .setStartDate(now)
                .setEndDate(end)
                .setSerialNumber(BigInteger.valueOf(1))
                .setSubject(new X500Principal("CN=" + alias))
                .build());
    } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }

    KeyPair kp = kpg.generateKeyPair();

    /*
 * Load the Android KeyStore instance using the the
 * "AndroidKeyStore" provider to list out what entries are
 * currently stored.
 */
    KeyStore ks = null;
    try {
        ks = KeyStore.getInstance("AndroidKeyStore");
        ks.load(null);
        Enumeration<String> aliases = ks.aliases();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    /*
 * Use a PrivateKey in the KeyStore to create a signature over
 * some data.
 */

    KeyStore.Entry entry = null;
    try {
        entry = ks.getEntry(alias, null);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (UnrecoverableEntryException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    }
    if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
        Log.w("E", "Not an instance of a PrivateKeyEntry");
    }
    else{
        Log.w("E", "Got Key!");
        privateKeyEntry = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
    }

}

And here is the code I am using for encrypt (encode) and decrypt (decode):

private String encryptString(String value){
    byte[] encodedBytes = null;
    try {
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
        cipher.init(Cipher.ENCRYPT_MODE,  privateKeyEntry );
        encodedBytes = cipher.doFinal(value.getBytes());
    } catch (Exception e) {
        e.printStackTrace();
    }

    return Base64.encodeToString(encodedBytes, Base64.DEFAULT);
}

private String decryptString(String value){
    byte[] decodedBytes = null;
    try {
        Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
        c.init(Cipher.DECRYPT_MODE,  privateKeyEntry );
        decodedBytes = c.doFinal(Base64.decode(value, Base64.DEFAULT));
    } catch (Exception e) {
        e.printStackTrace();
    }

    return new String(decodedBytes);
}

The Encryption appears to work fine but when I try to decrypt it I get the following error:

javax.crypto.BadPaddingException: error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02

Googling this seems to suggest that the private key used for decryption is different to the one used for decryption but in my code I use the exact same private key for both. I have also seen it suggested to set the key size manually but doing this in the KeyPairGenerator builder like this:

.setKeySize(1024);

Did not work and seems to be only available on API 19, I need to target API 18.

Can anyone help point me in the right direction as to a solution?

解决方案

You are not using the public key for encryption.

When you are using asymmetric encryption algorithms, you need to use the public key to encrypt your data, and the private key only to decrypt it again.

Besides encryption, you can also use the private key for signing, but that's not what you want here, so let's forget about that for the moment.

If you take the public key from the generated pair, when you encrypt your string, and the private key when decrypting, you should get the desired result. The public key you can extract by accessing the certificate from the keystore-object that holds your private key.

Alternatively you could also use a symmetric algorithm like AES and by that make your work a lot easier. Plus, symmetric algorithms are usually much faster, which is why asymmetric algorithms are never used purely, but in conjunction with symmetric algorithms, building so-called hybrid algorithms.

这篇关于Android - 编码&amp;用私钥解码RSA?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆