【发布时间】:2012-04-11 00:43:24
【问题描述】:
我使用KeyPairGenerator 生成了一个 RSA 密钥对。如果我没记错的话,KeyStore 仅用于存储证书而不是密钥。如何在计算机上正确存储私钥?
【问题讨论】:
我使用KeyPairGenerator 生成了一个 RSA 密钥对。如果我没记错的话,KeyStore 仅用于存储证书而不是密钥。如何在计算机上正确存储私钥?
【问题讨论】:
注意:此代码仅用于演示目的。将私钥存储在磁盘上时必须对其进行加密。不要按原样使用它。
你可以这样做:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.genKeyPair();
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(),
RSAPublicKeySpec.class);
saveToFile(PUBLIC_KEY_FILE,
pub.getModulus(), pub.getPublicExponent());
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(),
RSAPrivateKeySpec.class);
saveToFile(PRIVATE_KEY_FILE,
priv.getModulus(), priv.getPrivateExponent());
保存功能:
private static void saveToFile(String fileName,
BigInteger mod, BigInteger exp)
throws SomeException {
ObjectOutputStream oout = new ObjectOutputStream(
new BufferedOutputStream(new FileOutputStream(fileName)));
try {
oout.writeObject(mod);
oout.writeObject(exp);
} catch (Exception e) {
throw new SomeException(e);
} finally {
oout.close();
}
}
然后以同样的方式阅读:
private static PublicKey readPublicKey() throws SomeException {
InputStream in = new FileInputStream(PUBLIC_KEY_FILE);
ObjectInputStream oin =
new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
} catch (Exception e) {
throw new SomeException(e);
} finally {
oin.close();
}
}
读取私钥类似。
【讨论】:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 才能将其添加到 AndroidManifest.xml
keystore这意味着你没有回答问题
此代码块将生成 KeyPair 并将其存储在 AndroidKeyStore 上。 (注意:省略异常捕获)
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
String alias = "my_key"; // replace as required or get it as a function argument
int nBefore = keyStore.size(); // debugging variable to help convince yourself this works
// Create the keys if necessary
if (!keyStore.containsAlias(alias)) {
Calendar notBefore = Calendar.getInstance();
Calendar notAfter = Calendar.getInstance();
notAfter.add(Calendar.YEAR, 1);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
.setAlias(alias)
.setKeyType("RSA")
.setKeySize(2048)
.setSubject(new X500Principal("CN=test"))
.setSerialNumber(BigInteger.ONE)
.setStartDate(notBefore.getTime())
.setEndDate(notAfter.getTime())
.build();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
generator.initialize(spec);
KeyPair keyPair = generator.generateKeyPair();
}
int nAfter = keyStore.size();
Log.v(TAG, "Before = " + nBefore + " After = " + nAfter);
// Retrieve the keys
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
RSAPrivateKey privateKey = (RSAPrivateKey) privateKeyEntry.getPrivateKey();
RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();
Log.v(TAG, "private key = " + privateKey.toString());
Log.v(TAG, "public key = " + publicKey.toString());
【讨论】:
http://snipplr.com/view/18368/
或
http://docs.oracle.com/javase/1.5.0/docs/api/java/security/KeyStore.html
或
http://java.sun.com/docs/books/tutorial/security/apisign/vstep2.html 这是最有前途的
或
在不受信任的环境中保护密钥是不可能的。你可以混淆你的代码,你可以从任意变量创建一个密钥,无论如何。最终,假设您使用标准 javax.crypto 库,您必须调用 Mac.getInstance(),稍后您将在该实例上调用 init()。想要你的钥匙的人会得到它。
但是,我认为解决方案是将密钥与环境而非程序相关联。签名意味着数据来自已知来源,并且自该来源提供以来未被篡改。目前,您正试图说“保证我的程序产生了数据”。相反,将您的要求更改为“保证我的程序的特定用户生成数据”。然后将责任转移给该用户来照顾他/她的密钥。
【讨论】:
根据您的私钥格式,您可能需要将其转换为 java keytool 可以使用的格式。
但如果它是 keytool 支持的格式,您应该可以使用 keytool 导入它。 更多信息:
http://docs.oracle.com/javase/tutorial/security/toolfilex/rstep1.html
http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/keytool.html
【讨论】: