Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/vim/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中作为字符串变量的RSA公钥和私钥_Java_Security - Fatal编程技术网

Java中作为字符串变量的RSA公钥和私钥

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

出于明显的安全原因,我需要使用RSA私钥和公钥对用户的PIN码进行加密和解密,我找到了一个可行的解决方案,看起来像:

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的公钥格式
或者,添加标题/尾部以使其成为正确的PEM,使用OpenSSL将其转换为PKCS#8(未加密),同时还可以选择将其转换为二进制,并通过
generatePrivate
运行


类似地,您的公钥似乎是X.509 SubjectPublicKeyInfo编码的base64,OpenSSL(但不是OpenSSH)使用该编码,并且标准Java在名称“X.509”下支持该编码。因此,只需将base64转换为二进制,放入
X509EncodedKeySpec
,然后运行RSA
KeyFactory的
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
是合理的