我正在尝试使用Android 4.3中引入的Android密钥库提供程序生成和存储的私钥对Android上的字符串进行编码和解码
我可以使用以下代码成功生成并获取私钥:
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();
}
}
这是我用于加密(编码)和解密(解码)的代码:
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);
}
加密似乎工作正常,但当我尝试解密时,我收到以下错误:
javax.crypto.BadPaddingException: error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02
谷歌搜索似乎表明用于解密的私钥与用于解密的私钥不同,但在我的代码中,我使用完全相同的私钥。我也看到它建议手动设置密钥大小,但是在KeyPairGenerator构建器中这样做:
.setKeySize(1024);
没有用,似乎只能在API 19上使用,我需要针对API 18。
任何人都可以帮我指出解决方案的正确方向吗?
答案 0 :(得分:3)
您不使用公钥进行加密。
当您使用非对称加密算法时,您需要使用 公共密钥来加密您的数据, < em>私有密钥只能再次解密。
除了加密,您还可以使用私钥进行签名,但这不是您想要的,所以暂时不要忘记。
如果您从生成的对中获取公钥,则在加密字符串时以及解密时使用私钥时,您应该获得所需的结果。您可以通过访问保存私钥的密钥库对象中的 证书 来提取公钥。
或者您也可以使用像AES这样的对称算法,这样可以让您的工作变得更轻松。此外,对称算法通常要快得多,这就是为什么非对称算法从未纯粹使用,而是与对称算法结合,构建所谓的混合算法。
答案 1 :(得分:1)
签名生成与加密不同。如果要加密,则需要使用公钥进行加密并使用私钥进行解密。如果要生成签名,则需要使用私钥进行签名并使用公钥进行验证。这个顺序不能颠倒,也不能混合(安全)。