当前位置: 首页 > 知识库问答 >
问题:

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

习海
2023-03-14

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

共有3个答案

赵同
2023-03-14

我做了如下工作:

 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

冀嘉木
2023-03-14

在(大多数情况下)同意@JB的密码(通常)不应该被加密后,应该对密码进行“散列”——使用一种专门设计用于“拉伸”和salt的方法,比如scrypt,而不是像SHA-1这样的快速散列——同时还要注意,在原始代码中使用的RSA-512被破坏了,甚至在您的修改中显然使用的RSA-1024也被认为很弱:

您的Private ateKey值(从一开始)就显示为普通PKCS#1 DER编码的基数64,基本上仅由OpenSSL和使用OpenSSL(格式)的东西使用,如旧版本的OpenSSH。Java标准的“Sun”提供程序不处理这个问题,尽管我认为如果您想探索这个问题,BouncyCastle可能会处理。对于Sun,您需要将其从base 64转换为二进制DER;将其包装成PKCS#8格式(二进制格式只是添加一个头,也许是EOC拖车,因为PKCS#8用于RSA的算法特定部分是PKCS#1);并将其放入PKCS8EncodedKeySpec中,并通过RSA类型的KeyFactory的GeneratePrivate运行

  • http://docs.oracle.com/javase/8/docs/api/java/util/Base64.html(仅限Java8)
  • http://docs.oracle.com/javase/8/docs/api/java/security/KeyFactory.html
  • https://www.rfc-editor.org/rfc/rfc5208#section-5未加密PKCS#8的结构(Java没有执行第6节中的加密格式),并查看RSA的OID的公钥形式。

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

类似地,您的公钥似乎是X.509 SubjectPublicKeyInfo编码的base64,OpenSSL(但不是OpenSSH)使用该编码,标准Java在名称“X.509”下支持该编码。因此,只需将base64转换为二进制,放入X509EncodedKeySpec,然后运行RSAKeyFactory的generatePublic。注意:如果加密将在远程或分布式进行,这是公钥加密的常见情况,则加密机必须确保使用正确的公钥;如果攻击者可以替换错误的公钥,他们可以解密并窃取至少一些您认为安全的数据。这就是为什么真正的PK系统不使用普通公钥,而是使用证书,比如SSL/TLS和s/MIME之类的X.509,或者PGP之类的信任网。

费学
2023-03-14

如果我了解您想要什么,要从静态变量中获取PublicKey和PrivateKey实例,您可以这样做,例如:

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

    }
}
 类似资料:
  • 如何使用作为字符串提供的公共和私有RSA密钥进行加密和解密。因为我正在使用RSACryptoServiceProvider,它需要XML格式,所以是否有可能使用提供的字符串。谢谢。

  • 我想得到一个文件内容的公钥,这是一个文件内容看起来像什么的例子(用生成): 如果我是对的,这不是公钥,但是可以从这个字符串中获取公钥。 这个答案回答了我的问题https://stackoverflow.com/a/19387517/2735398 但答案似乎不起作用。我有个例外: 当看到答案的评论时,我不是唯一有问题的人... 如何修复异常?或者有没有其他方法可以从字符串中获取公钥?

  • 我可以直接从文件中读取公钥和私钥,因为文件流将其转换为PublicKey和PrivateKey对象。但如果以字符串形式加载,则失败。 工作代码 线程“main”java.security.spec.invalidkeyspection:java.security.invalidkeyexception:sun.security.rsa.rsakeyfactory.engineGeneratePub

  • 在Android中,我使用下面的代码将String转换为RSA私钥 https://www.devglan.com/online-tools/rsa-encryption-decryption 但是,当我使用这个网站时,我的代码不起作用。 https://8gwifi.org/RSAFunctionality?keysize=1024 我在Android studio中的代码是: 与第二个链接错误

  • 我一直在阅读一些RSA文献和堆栈溢出问题,但我没有得到明确的答案。 仅给定一个RSA私钥模和私钥指数,这是我所拥有的全部(也足够用于所有密码相关操作),我能得到相关的公钥模和公钥指数吗? 另外,我是否可以仅用这两个参数获得私钥的编码形式?我在java中尝试了以下方法(java不是实际的请求),但是支持它的OpenSSL引擎失败,错误为:04000090:RSA例程:openSSL_internal

  • 我有一个公钥和一个私钥,还有一个字符串,我想要解密。 公钥的格式如下: 私钥的格式如下: 我要解密的字符串已经使用公钥加密,然后我需要使用私钥解密它。