简体   繁体   English

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

[英]RSA public and private key as String variables in Java

For obvious security reasons i need to encrypt and decrypt User's PIN codes with RSA private and public key, I have found working solution, which looks like:出于明显的安全原因,我需要使用 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));

}

everything works fine, but in this example key-pair is not static and generate new values everytime, but I need to use same keys, which are represented as String variables:一切正常,但在此示例中,密钥对不是静态的,每次都会生成新值,但我需要使用相同的密钥,这些密钥表示为字符串变量:

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";

Is there any way to cast these variables to PublicKey and PrivateKey Class?有没有办法将这些变量转换为 PublicKey 和 PrivateKey 类?

If I understand what you want, to obtain PublicKey and PrivateKey instances from your static variables you can do, for example, this way:如果我明白你想要什么,从你的静态变量中获取 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) {

    }
}

After (mostly) concurring with @JB that passwords (usually) shouldn't be encrypted, they should be "hashed" -- using a method specifically designed to "stretch" and salt such as scrypt, not a fast hash like SHA-1 -- and also noting that RSA-512 as used in your original code is broken and even RSA-1024 as apparently used in your modification is considered weak:在(大多数情况下)同意@JB 不应该对密码(通常)进行加密之后,它们应该被“散列”——使用专门设计用于“拉伸”加盐的方法,例如 scrypt,而不是像 SHA-1 这样的快速散列-- 还要注意原始代码中使用的 RSA-512 已损坏,甚至在您的修改中明显使用的 RSA-1024 也被认为是弱的:

Your PrivateKey value appears (from its beginning) to be base64 of a plain PKCS#1 DER encoding, which basically is used only by OpenSSL and things that use OpenSSL (format) like older versions of OpenSSH.您的 PrivateKey 值(从一开始)似乎是普通 PKCS#1 DER 编码的 base64,它基本上只由 OpenSSL 和使用 OpenSSL(格式)的东西使用,如旧版本的 OpenSSH。 The Java standard "Sun" providers do not handle this, although I think BouncyCastle might if you want to explore that. Java 标准的“Sun”提供程序不处理这个问题,尽管我认为 BouncyCastle 可能会在您想要探索它的情况下处理。 For Sun you need to convert it to binary DER from base64;对于 Sun,您需要将其从 base64 转换为二进制 DER; wrap it into PKCS#8 format (which in binary is just adding a header and maybe EOC trailers because the algorithm-specific part of PKCS#8 for RSA is PKCS#1);将它包装成 PKCS#8 格式(二进制只是添加一个标题,也许是 EOC 尾部,因为用于 RSA 的 PKCS#8 的算法特定部分PKCS#1); and put it in a PKCS8EncodedKeySpec and run it through generatePrivate of a KeyFactory of type RSA.并将其放入PKCS8EncodedKeySpec并通过 RSA 类型的KeyFactorygeneratePrivate运行它。 See

Alternatively add the header/trailer to make it proper PEM, use OpenSSL to convert it to PKCS#8 (unencrypted), and optionally binary at the same time, and run that through generatePrivate .或者,添加标头/预告片以使其成为正确的 PEM,使用 OpenSSL 将其转换为 PKCS#8(未加密),并可选择同时转换为二进制,然后通过generatePrivate运行它。

Your PublicKey similarly appears to be base64 of an X.509 SubjectPublicKeyInfo encoding, which OpenSSL (but not OpenSSH) uses and standard Java does support under the name "X.509".您的 PublicKey 类似地似乎是 X.509 SubjectPublicKeyInfo 编码的 base64,OpenSSL(但不是 OpenSSH)使用该编码并且标准 Java确实支持名称“X.509”。 So just convert from base64 to binary, put in an X509EncodedKeySpec , and run through generatePublic of the RSA KeyFactory .所以只需从 base64 转换为二进制,放入X509EncodedKeySpec ,并通过 RSA KeyFactory generatePublic运行。 Note if your encryption will be done remote or distributed, which is the usual scenario for publickey-encryption, the encryptor must be certain to use the correct publickey;请注意,如果您的加密是远程或分布式完成的(这是公钥加密的常见场景),则加密者必须确保使用正确的公钥; if an attacker can substitute a wrong publickey they can decrypt and steal at least some of your supposedly secure data.如果攻击者可以替换错误的公钥,他们就可以解密并窃取至少一些您认为是安全的数据。 That's why real PK systems don't use a plain publickey, they use a certificate, either X.509 like SSL/TLS and S/MIME, or web-of-trust like PGP.这就是为什么真正的 PK 系统不使用普通公钥,它们使用证书,或者像 SSL/TLS 和 S/MIME 这样的 X.509,或者像 PGP 这样的信任网络。

I got this running doing the following:我执行以下操作:

 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);
  }

You must also to remove -----BEGIN PRIVATE KEY----- , -----END PRIVATE KEY----- and all \\n from the strings that contain you keys.您还必须从包含您的密钥的字符串中删除-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----和所有\\n

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM