How to create RSA PrivateKey from string with RSAPrivateKeySpec class in Java?

≯℡__Kan透↙ 提交于 2021-01-27 22:07:07

问题


I have the below information and want to generate a public and private key in RSA (Java).

    String pubKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJXFRUWMDJZ+moC/VbcAXoY5dDxOruwI2B+B+YZRHSRRTKPyd9v0HTqdLeVgufLu/cSxlZAKtZDp9mfgyNdbY9ECAwEAAQ==";
    String privKey = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAlcVFRYwMln6agL9VtwBehjl0PE6u7AjYH4H5hlEdJFFMo/J32/QdOp0t5WC58u79xLGVkAq1kOn2Z+DI11tj0QIDAQABAkBC1Bp71OkNAgL47edWWADVja9y9X0R70RYkst/hpQlTrjN4QxzN4k4gCqqdFkno2LfacRO7igMQuVEmYujfkbNAiEA/lU1CyW9J65FXSObsBLxqlNpFw79B2EKUkT6o7b2Ez8CIQCWwJlIyDaoXt7CrvTrPDpok7U93ZKmDPiRjjXDPsGU7wIhAJ6pITIXFO2QNg1ojVNGPiR3bHPKEedsjjfMeF9xYAmZAiAQnfpHg4pC1PJJE2/73g+yJ1X7E8ludE+R+9MBSpGcEQIgBWaVSyTx4e+gSulT93vnMpVsYmiwe53e5t4Uxs+cgSE=";
    String nModulusPublic = "AJXFRUWMDJZ-moC_VbcAXoY5dDxOruwI2B-B-YZRHSRRTKPyd9v0HTqdLeVgufLu_cSxlZAKtZDp9mfgyNdbY9E=";
    String eExponentPublic = "AQAB";
    String nModulusPrivate = "AJXFRUWMDJZ-moC_VbcAXoY5dDxOruwI2B-B-YZRHSRRTKPyd9v0HTqdLeVgufLu_cSxlZAKtZDp9mfgyNdbY9E=";
    String eExponentPrivate = "QtQae9TpDQIC-O3nVlgA1Y2vcvV9Ee9EWJLLf4aUJU64zeEMczeJOIAqqnRZJ6Ni32nETu4oDELlRJmLo35GzQ==";

These are main Encryption and decryption functions :

static String Decrypt(String encodedString,PrivateKey privKey) {
    try {
        Cipher cipher = Cipher.getInstance(cipherInstancename);
        cipher.init(Cipher.DECRYPT_MODE, privKey);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encodedString));
        return new String(decrypted, "UTF-8");
    } catch (Exception err) {
        return err.fillInStackTrace().toString();
    }
}

static String Encrypt(String encodedString,PublicKey pubKey) {
    try {
        Cipher cipher = Cipher.getInstance(cipherInstancename);
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        byte[] plainBytes = new String(encodedString).getBytes("UTF-8");
        byte[] cipherData = cipher.doFinal(plainBytes);
        String encryptedString = Base64.getEncoder().encodeToString(cipherData);
        return encryptedString;
    } catch (Exception err) {
        return err.fillInStackTrace().toString();
    }
}

If I create PrivateKey and PublicKey with below function everything works great:

 static PrivateKey firstPrivateKey(String privateKeyStr) throws Exception {
    byte[] keyBytes = Base64.getDecoder().decode(privateKeyStr.getBytes(StandardCharsets.UTF_8));
    PKCS8EncodedKeySpec specPrivate = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey fileGeneratedPrivateKey = keyFactory.generatePrivate(specPrivate);
    RSAPrivateKey rsaPrv  = (RSAPrivateKey)(fileGeneratedPrivateKey);
    return  rsaPrv;
}
 static PublicKey firstPublicKey(String publicKeyStr) throws Exception {
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");

    byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr.getBytes(StandardCharsets.UTF_8));
    X509EncodedKeySpec specPublic = new X509EncodedKeySpec(keyBytes);
    PublicKey fileGeneratedPublicKey = keyFactory.generatePublic(specPublic);
    RSAPublicKey rsaPub  = (RSAPublicKey)(fileGeneratedPublicKey);
    return  rsaPub;
}

But I want to create them by this way with below function but decryption does not work:

 static PublicKey secondPublicKey(String publicKString,String publicExponentStr) throws Exception {
    byte[] modulusBytes = Base64.getDecoder().decode(publicKString);
    byte[] exponentBytes = Base64.getDecoder().decode(publicExponentStr);
    BigInteger modulus = new BigInteger(1, modulusBytes);
    BigInteger exponent = new BigInteger(1, exponentBytes);

    RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PublicKey pubKey = fact.generatePublic(rsaPubKey);
    return pubKey;
}

static PrivateKey secondPrivateKey(String privateKString,String privateExponentStr) throws Exception {
    byte[] modulusBytes = Base64.getDecoder().decode(privateKString);
    byte[] exponentBytes = Base64.getDecoder().decode(privateExponentStr);
    BigInteger modulus = new BigInteger(1, modulusBytes);
    BigInteger exponent = new BigInteger(1, exponentBytes);

    RSAPrivateKeySpec privSpec = new RSAPrivateKeySpec(modulus,exponent);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PrivateKey privKey = fact.generatePrivate(privSpec);

    return privKey;
}

Using firstPrivateKey and firstPublicKey key generators and work nice:

   String a = Encrypt("test",firstPrivateKey(pubKey));
   String b = Decrypt(a, firstPublicKey(privKey));
   System.out.println(b);

Using second functions and does not work:

 String a = Encrypt("test",secondPublicKey(pubKey,eExponentPublic));
 String b = Decrypt(a, secondPrivateKey(privKey,eExponentPrivate));
 System.out.println(b);

What's the problem with secondPublicKey and secondPrivateKey functions?

Update:

I generate all keys and Modulus from this code, It seems my decoding is not ok:

    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    // RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(1024, RSAKeyGenParameterSpec.F4);
    kpg.initialize( 512 );
    KeyPair kp = kpg.generateKeyPair();
    String publicKeyStr = Base64.getEncoder().encodeToString(kp.getPublic().getEncoded());
    String privateKeyStr = Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded());

    KeyFactory keyFactory = KeyFactory.getInstance("RSA");

    byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr.getBytes(StandardCharsets.UTF_8));
    X509EncodedKeySpec specPublic = new X509EncodedKeySpec(keyBytes);
    PublicKey fileGeneratedPublicKey = keyFactory.generatePublic(specPublic);
    RSAPublicKey rsaPub  = (RSAPublicKey)(fileGeneratedPublicKey);

    keyBytes = Base64.getDecoder().decode(privateKeyStr.getBytes(StandardCharsets.UTF_8));
    PKCS8EncodedKeySpec specPrivate = new PKCS8EncodedKeySpec(keyBytes);
    PrivateKey fileGeneratedPrivateKey = keyFactory.generatePrivate(specPrivate);
    RSAPrivateKey rsaPrv  = (RSAPrivateKey)(fileGeneratedPrivateKey);


    BigInteger publicKeyModulus = rsaPub.getModulus();
    BigInteger publicKeyExponent  = rsaPub.getPublicExponent();
    BigInteger privateKeyModulus = rsaPrv.getModulus();
    BigInteger privateKeyExponent  = rsaPrv.getPrivateExponent();


    String nModulusPublic=Base64.getUrlEncoder().encodeToString(publicKeyModulus.toByteArray());
    String eExponentPublic=Base64.getUrlEncoder().encodeToString(publicKeyExponent.toByteArray());
    String nModulusPrivate=Base64.getUrlEncoder().encodeToString(privateKeyModulus.toByteArray());
    String eExponentPrivate=Base64.getUrlEncoder().encodeToString(privateKeyExponent.toByteArray());

    System.out.println(publicKeyStr);
    System.out.println(privateKeyStr);
    System.out.println( nModulusPublic);
    System.out.println(eExponentPublic);
    System.out.println( nModulusPrivate);
    System.out.println(eExponentPrivate);

回答1:


A related public and private key have the same modulus. Therefore the distinction between nModulusPublic and nModulusPrivate is actually not necessary (unlike the public and private exponent).

secondPublicKey() and secondPrivateKey() expect the modulus (nModulusPublic or the identical nModulusPrivate) as first argument. Instead, the entire key (pubKey or privKey) is passed, which causes the error. If the modulus is passed instead, it works.

By the way, modulus and exponent are Base64url encoded and must first be converted to the standard Base64 encoding (- -> + and _ -> /). Alternatively the Base64url decoder can be used in secondPublicKey() or secondPrivateKey() (Base64.getUrlDecoder()).

Since the two public or private keys are identical (only with different formats) any public/private key combination is possible for encryption/deryption:

String pubKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJXFRUWMDJZ+moC/VbcAXoY5dDxOruwI2B+B+YZRHSRRTKPyd9v0HTqdLeVgufLu/cSxlZAKtZDp9mfgyNdbY9ECAwEAAQ==";
String privKey = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAlcVFRYwMln6agL9VtwBehjl0PE6u7AjYH4H5hlEdJFFMo/J32/QdOp0t5WC58u79xLGVkAq1kOn2Z+DI11tj0QIDAQABAkBC1Bp71OkNAgL47edWWADVja9y9X0R70RYkst/hpQlTrjN4QxzN4k4gCqqdFkno2LfacRO7igMQuVEmYujfkbNAiEA/lU1CyW9J65FXSObsBLxqlNpFw79B2EKUkT6o7b2Ez8CIQCWwJlIyDaoXt7CrvTrPDpok7U93ZKmDPiRjjXDPsGU7wIhAJ6pITIXFO2QNg1ojVNGPiR3bHPKEedsjjfMeF9xYAmZAiAQnfpHg4pC1PJJE2/73g+yJ1X7E8ludE+R+9MBSpGcEQIgBWaVSyTx4e+gSulT93vnMpVsYmiwe53e5t4Uxs+cgSE=";
String nModulusPublic = "AJXFRUWMDJZ-moC_VbcAXoY5dDxOruwI2B-B-YZRHSRRTKPyd9v0HTqdLeVgufLu_cSxlZAKtZDp9mfgyNdbY9E=".replace("-", "+").replace("_","/");
String eExponentPublic = "AQAB".replace("-", "+").replace("_","/");
String nModulusPrivate = "AJXFRUWMDJZ-moC_VbcAXoY5dDxOruwI2B-B-YZRHSRRTKPyd9v0HTqdLeVgufLu_cSxlZAKtZDp9mfgyNdbY9E=".replace("-", "+").replace("_","/");
String eExponentPrivate = "QtQae9TpDQIC-O3nVlgA1Y2vcvV9Ee9EWJLLf4aUJU64zeEMczeJOIAqqnRZJ6Ni32nETu4oDELlRJmLo35GzQ==".replace("-", "+").replace("_","/");    

String a, b;

// first/first
a = Encrypt("test", firstPublicKey(pubKey));
b = Decrypt(a, firstPrivateKey(privKey));
System.out.println(b);

// second/second
a = Encrypt("test", secondPublicKey(nModulusPublic, eExponentPublic));
b = Decrypt(a, secondPrivateKey(nModulusPrivate, eExponentPrivate));
System.out.println(b);

// first/second
a = Encrypt("test", firstPublicKey(pubKey));
b = Decrypt(a, secondPrivateKey(nModulusPrivate, eExponentPrivate));
System.out.println(b);

// second/first
a = Encrypt("test", secondPublicKey(nModulusPublic, eExponentPublic));
b = Decrypt(a, firstPrivateKey(privKey));
System.out.println(b);

Note that there is a typo in the posted code: Encrypt is used in combination with firstPrivateKey() and Decrypt in combination with firstPublicKey().



来源:https://stackoverflow.com/questions/63647609/how-to-create-rsa-privatekey-from-string-with-rsaprivatekeyspec-class-in-java

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!