Java中作为字符串变量的RSA公钥和私钥
出于明显的安全原因,我需要使用RSA私钥和公钥对用户的PIN码进行加密和解密,我找到了一个可行的解决方案,看起来像:Java中作为字符串变量的RSA公钥和私钥,java,security,Java,Security,出于明显的安全原因,我需要使用RSA私钥和公钥对用户的PIN码进行加密和解密,我找到了一个可行的解决方案,看起来像: KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(512); KeyPair rsaKeyPair = kpg.genKeyPair(); byte[] txt = "This is a secret message.".getBytes(); Sy
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(512);
KeyPair rsaKeyPair = kpg.genKeyPair();
byte[] txt = "This is a secret message.".getBytes();
System.out.println("Original clear message: " + new String(txt));
// encrypt
Cipher cipher;
try {
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, rsaKeyPair.getPublic());
txt = cipher.doFinal(txt);
} catch (Throwable e) {
e.printStackTrace();
return;
}
System.out.println("Encrypted message: " + new String(txt));
// decrypt
try {
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, rsaKeyPair.getPrivate());
txt = cipher.doFinal(txt);
} catch (Throwable e) {
e.printStackTrace();
return;
}
System.out.println("Decrypted message: " + new String(txt));
}
一切正常,但在本例中,键对不是静态的,每次都会生成新值,但我需要使用相同的键,它们表示为字符串变量:
public static final String PrivateKey = "MIICXAIBAAKBgQDx0PSJr6zEP9914k1eM+sS8/eW+FenhBQI/jf6ARe8kZHFig9Y"
+ bla bla bla
+ "wdK3jBzObK319yNFr/2LukNZ9Bgv7fS78roBvxbe2gI=";
public static final String PublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDx0PSJr6zEP9914k1eM+sS8/eW"
+ bla bla bla
+ "jYo5w2Nhxe2cukCQMQIDAQAB";
有没有办法将这些变量强制转换为PublicKey和PrivateKey类?在(大多数情况下)同意@JB的密码(通常)不应加密后,应该对密码进行“哈希”——使用专门设计的“拉伸”和salt方法,如scrypt,不是像SHA-1那样的快速散列——还要注意的是,在原始代码中使用的RSA-512被破坏了,甚至在您的修改中使用的RSA-1024也被认为很弱:
您的PrivateKey值(从一开始)似乎是普通PKCS#1 DER编码的base64,基本上只有OpenSSL和使用OpenSSL(格式)的东西(如早期版本的OpenSSH)才使用它。Java标准的“Sun”提供程序不处理这个问题,尽管我认为BouncyCastle可能会处理这个问题,如果您想探究的话。对于Sun,您需要将其从base64转换为二进制DER;将其包装成PKCS#8格式(二进制格式只是添加一个标题,可能还有EOC拖尾,因为RSA的PKCS#8的算法特定部分是PKCS#1);然后将其放入一个PKCS8EncodedKeySpec
中,并通过RSA类型的KeyFactory
的generatePrivate
运行它。看
- (仅限Java8)
- 有关未加密PKCS#8的结构(Java不采用第6节中的加密格式),请查看RSA OID的公钥格式
generatePrivate
运行
类似地,您的公钥似乎是X.509 SubjectPublicKeyInfo编码的base64,OpenSSL(但不是OpenSSH)使用该编码,并且标准Java在名称“X.509”下支持该编码。因此,只需将base64转换为二进制,放入
X509EncodedKeySpec
,然后运行RSAKeyFactory的generatePublic
。注意:如果加密将在远程或分布式进行(这是公钥加密的常见情况),则加密机必须确保使用正确的公钥;如果攻击者可以替换错误的公钥,他们可以解密并窃取至少一些您认为安全的数据。这就是为什么真正的PK系统不使用普通公钥,它们使用证书,或者像SSL/TLS和s/MIME这样的X.509,或者像PGP这样的信任网。如果我了解您想要什么,要从静态变量中获取公钥和私钥实例,您可以这样做,例如:
private static final String privateKeyString = "...";
private static PrivateKey privateKey;
private static final String publicKeyString = "...";
private static PublicKey publicKey;
static {
KeyFactory kf;
try {
kf = KeyFactory.getInstance("RSA");
byte[] encodedPv = Base64.decodeBase64(privateKeyString);
PKCS8EncodedKeySpec keySpecPv = new PKCS8EncodedKeySpec(encodedPv);
privateKey = kf.generatePrivate(keySpecPv);
byte[] encodedPb = Base64.decodeBase64(publicKeyString);
X509EncodedKeySpec keySpecPb = new X509EncodedKeySpec(encodedPb);
publicKey = kf.generatePublic(keySpecPb);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
}
}
我通过以下方式运行此程序:
公钥loadPrivateKey(存储字符串)引发GeneralSecurityException{
PKCS8EncodedKeySpec密钥规范=
新PKCS8EncodedKeySpec(
Base64.getDecoder().decode(存储的.getBytes(StandardCharsets.UTF_8));
KeyFactory kf=KeyFactory.getInstance(“RSA”);
返回kf.generatePrivate(keySpec);
}
公钥loadPublicKey(存储字符串)引发GeneralSecurityException{
byte[]data=Base64.getDecoder().decode(存储的.getBytes(StandardCharsets.UTF_8));
X509EncodedKeySpec=新X509EncodedKeySpec(数据);
KeyFactory事实=KeyFactory.getInstance(“RSA”);
返回事实。generatePublic(spec);
}
您还必须从包含密钥的字符串中删除----开始私钥---
,----结束私钥---
和所有\n
。公钥
和私钥
不是类,它们是您实现的接口。您永远不应该加密密码。密码应该是咸的和散列的。@EddyG我看不出有问题。在此上下文中,“静态密钥”显然是指加密密钥(对),对于程序的每次运行和/或调用不会改变;它与Java“静态”字段、方法或嵌套类没有直接关系。在源代码中放置一个“长期”键是可疑的,但是如果使用静态final String
是合理的