RSA公钥和私钥作为Java中的String变量

时间:2015-04-02 11:54:43

标签: java security

出于明显的安全原因,我需要使用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));

}

一切正常,但在这个示例中,密钥对不是静态的,每次都会生成新值,但我需要使用相同的密钥,它们表示为String变量:

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 Class?

3 个答案:

答案 0 :(得分:1)

如果我理解你想要什么,从你的静态变量中获取公钥和私钥实例,你可以这样做,例如,这样:

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) {

    }
}

答案 1 :(得分:0)

在(大多数情况下)同意@JB之后,密码(通常)不应该被加密,它们应该是"哈希" - 使用专门为"伸展" 盐如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并运行generatePrivate类型的RSA KeyFactory。见

或者添加标题/预告片以使其成为正确的PEM,使用OpenSSL将其转换为PKCS#8(未加密),并同时选择二进制,并通过generatePrivate运行。

你的PublicKey同样似乎是X.509 SubjectPublicKeyInfo编码的base64,OpenSSL(但不是OpenSSH)使用它,标准Java 支持名称" X.509&#34 ;。因此,只需将base64转换为二进制文件,放入X509EncodedKeySpec,然后运行RSA generatePublic的{​​{1}}。请注意,如果您的加密是远程或分布式的,这是publickey-encryption的常用方案,加密器必须确保使用正确的公钥;如果攻击者可以替换错误的公钥,他们可以解密并窃取至少一些你所谓的安全数据。这就是为什么真正的PK系统不使用普通公钥,他们使用证书,如X.509,如SSL / TLS和S / MIME,或者像PGP一样的信任网。

答案 2 :(得分:0)

我正在执行以下操作:

 public Key loadPrivateKey(String stored) throws GeneralSecurityException {
    PKCS8EncodedKeySpec keySpec =
        new PKCS8EncodedKeySpec(
            Base64.getDecoder().decode(stored.getBytes(StandardCharsets.UTF_8)));
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePrivate(keySpec);
  }

  public Key loadPublicKey(String stored) throws GeneralSecurityException {
    byte[] data = Base64.getDecoder().decode(stored.getBytes(StandardCharsets.UTF_8));
    X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    return fact.generatePublic(spec);
  }

您还必须从包含您的密钥的字符串中删除-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----和所有\n