简体   繁体   English

Java:RSA 加密问题

[英]Java: RSA Encryption issue

Small question regarding a Java code for RSA please.关于 RSA 的 Java 代码的小问题。

I am having a very simple piece of Java code.我有一段非常简单的 Java 代码。


import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

public class RSA {

    public static void main(String[] args) throws Exception {
        String privateKeyString = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER+iccdhb474gKs6QE9c3JNS3BMlPTyFD2EOP3/NSrBlZtvVpKyQdHxYZ0W6a/IixWc0WjDqqcVAtrwCILmHU7Q==";
        String publicKeyString = "MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCyp0Sx3AgDhXYN3ecGaFYt51dnlrbgJJoRnYMh52QmDg=";

        String              secretMessage = "My TOP SECRET Message";

        byte[]              buffer1       = Base64.getDecoder().decode(privateKeyString);
        PKCS8EncodedKeySpec keySpec1      = new PKCS8EncodedKeySpec(buffer1);
        KeyFactory          keyFactory1   = KeyFactory.getInstance("RSA");
        PrivateKey          privateKey    = (RSAPrivateKey) keyFactory1.generatePrivate(keySpec1);

        byte[]             buffer2     = Base64.getDecoder().decode(publicKeyString);
        KeyFactory         keyFactory2 = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec keySpec2      = new PKCS8EncodedKeySpec(buffer2);
        PublicKey          publicKey   = (RSAPublicKey) keyFactory2.generatePublic(keySpec2);

        Cipher encryptCipher = Cipher.getInstance("RSA");
        encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);

        byte[] secretMessageBytes    = secretMessage.getBytes(StandardCharsets.UTF_8);
        byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessageBytes);
        String encodedMessage        = Base64.getEncoder().encodeToString(encryptedMessageBytes);

        Cipher decryptCipher = Cipher.getInstance("RSA");
        decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);

        byte[] decryptedMessageBytes = decryptCipher.doFinal(encryptedMessageBytes);
        String decryptedMessage      = new String(decryptedMessageBytes, StandardCharsets.UTF_8);

        System.out.println("Step 1" + secretMessage);
        System.out.println("Step 2" + encodedMessage);
        System.out.println("Step 3" + decryptedMessage);
    }
    
}

I would have expected this to work, and be able to see some kind of gibberish for "Step 2"我本以为这会起作用,并且能够看到“第 2 步”的一些乱码

But instead, I am seeing this:但是相反,我看到了这个:

Exception in thread "main" java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : DER input, Integer tag error
    at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:251)
    at java.base/java.security.KeyFactory.generatePrivate(KeyFactory.java:390)

May I ask what is wrong with this piece of code please?请问这段代码有什么问题吗?

Thank you谢谢

In the code there are the following issues:代码中存在以下问题:

  • A private and public EC key are imported (additionally, both keys are swapped).导入私钥和公钥 EC(另外,交换两个密钥)。 Since RSA encryption is to be performed, RSA keys are to be used instead.由于要执行 RSA 加密,因此要使用 RSA 密钥。
  • The public key is imported with PKCS8EncodedKeySpec .公钥是用PKCS8EncodedKeySpec导入的。 However, PKCS8EncodedKeySpec is intended for importing a private PKCS#8 key.但是, PKCS8EncodedKeySpec用于导入私有 PKCS#8 密钥。 Since a public X.509/SPKI key is to be imported, X509EncodedKeySpec has to be used instead.由于要导入公共 X.509/SPKI 密钥,因此必须X509EncodedKeySpec
  • When instantiating the Cipher object, only the algorithm is specified ( RSA ), but not the padding.实例化Cipher object 时,仅指定算法 ( RSA ),而不指定填充。 Therefore, a provider-dependent default value is used for the padding.因此,提供者相关的默认值用于填充。 To avoid unintentional use of an incorrect padding and cross-platform problems, the padding should also be explicitly specified instead (eg RSA/ECB/PKCS1Padding ).为避免无意中使用不正确的填充和跨平台问题,还应明确指定填充(例如RSA/ECB/PKCS1Padding )。

The fixed code is as follows:固定代码如下:

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class MyClass {
    public static void main(String args[]) throws Exception {
        
        // Fix 1: Use RSA keys: The private RSA key is a 2048 bit DER encoded PKCS#8 key (Base64 encoded). The public RSA key is the associated 2048 bit DER encoded X.509/SPKI key (Base64 encoded). Check the RSA keys with an ASN.1 parser, e.g. https://lapo.it/asn1js/.  
        String privateKeyString = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6cXloNrocJ8swwj8xktPmEOTfTgJT7KkUwWIGOjBB1QxApgdn5+SUHsakvEJq3Fgn+FnuuN8cfcqWrbT9jURtgNGinJNJ+StPM/PCxfhSv+XbkK11CV2EcJMyDB/8S/9u4E2ht/N1kT4OF2/mVDAq2MjjeUMq8CLmQR63ZMXB8lwmsGJEl4Rwt9WBZNcZFCfuCeBYrKRS7mtLzd4BTXEf0UuiNB/KJrz38TKSI47v/dRbB34wBNn0cuNLHb8t/eDaOvzV6J8SZgOWuL85mng6Fm77QGjUteWgJN76+YhDZgJfsRq1Q67JAy3ZXDHi5X538DcM/o+0wYEqkXxK3iIbAgMBAAECggEASlJj0ExIomKmmBhG8q8SM1s2sWG6gdQMjs6MEeluRT/1c2v79cq2Dum5y/+UBl8x8TUKPKSLpCLs+GXkiVKgHXrFlqoN+OYQArG2EUWzuODwczdYPhhupBXwR3oX4g41k/BsYfQfZBVzBFEJdWrIDLyAUFWNlfdGIj2BTiAoySfyqmamvmW8bsvc8coiGlZ28UC85/Xqx9wOzjeGoRkCH7PcTMlc9F7SxSthwX/k1VBXmNOHa+HzGOgO/W3k1LDqJbq2wKjZTW3iVEg2VodjxgBLMm0MueSGoI6IuaZSPMyFEM3gGvC2+cDBI2SL/amhiTUa/VDlTVw/IKbSuar9uQKBgQDd76M0Po5Lqh8ZhQ3obhFqkfO5EBXy7HUL15cw51kVtwF6Gf/J2HNHjwsg9Nb0eJETTS6bbuVd9bn884JoRS986nVTFNZ4dnjEgKjjQ8GjfzdkpbUxsRLWiIxuOQSpIUZGdMi2ctTTtspvMsDsjRRYdYIQCe/SDsdHGT3vcUCybwKBgQDXDz6iVnY84Fh5iDDVrQOR4lYoxCL/ikCDJjC6y1mjR0eVFdBPQ4j1dDSPU9lahBLby0VyagQCDp/kxQOl0z2zBLRI4I8jUtz9/9KW6ze7U7dQJ7OTfumd5I97OyQOG9XZwKUkRgfyb/PAMBSUSLgosi38f+OC3IN3qlvHFzvxFQKBgQCITpUDEmSczih5qQGIvolN1cRF5j5Ey7t7gXbnXz+Umah7kJpMIvdyfMVOAXJABgi8PQwiBLM0ySXo2LpARjXLV8ilNUggBktYDNktc8DrJMgltayaj3HNd2IglD5rjfc2cKWRgOd7/GlKcHaTEnbreYhfR2sWrWLxJOyoMfuVWwKBgFalCbMV6qU0LfEo8aPlBN8ttVDPVNpntP4h0NgxPXgPK8Pg+gA1UWSy4MouGg/hzkdHaj9ifyLlCX598a5JoT4S0x/ZeVHd/LNI8mtjcRzD6cMde7gdFbpLb5NSjIAyrsIAX4hxvpnqiOYRePkVIz0iLGziiaMbfMwlkrxvm/LRAoGBALPRbtSbE2pPgvOHKHTGPr7gKbmsWVbOcQA8rG801T38W/UPe1XtynMEjzzQ29OaVeQwvUN9+DxFXJ6Yvwj6ih4Wdq109i7Oo1fDnMczOQN9DKch2eNAHrNSOMyLDCBm++wbyHAsS2T0VO8+gzLABviZm5AFCQWfke4LZo5mOS10";
        String publicKeyString = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAunF5aDa6HCfLMMI/MZLT5hDk304CU+ypFMFiBjowQdUMQKYHZ+fklB7GpLxCatxYJ/hZ7rjfHH3Klq20/Y1EbYDRopyTSfkrTzPzwsX4Ur/l25CtdQldhHCTMgwf/Ev/buBNobfzdZE+Dhdv5lQwKtjI43lDKvAi5kEet2TFwfJcJrBiRJeEcLfVgWTXGRQn7gngWKykUu5rS83eAU1xH9FLojQfyia89/EykiOO7/3UWwd+MATZ9HLjSx2/Lf3g2jr81eifEmYDlri/OZp4OhZu+0Bo1LXloCTe+vmIQ2YCX7EatUOuyQMt2Vwx4uV+d/A3DP6PtMGBKpF8St4iGwIDAQAB";

        String              secretMessage = "My TOP SECRET Message";

        byte[]              buffer1       = Base64.getDecoder().decode(privateKeyString);
        PKCS8EncodedKeySpec keySpec1      = new PKCS8EncodedKeySpec(buffer1);
        KeyFactory          keyFactory1   = KeyFactory.getInstance("RSA");
        PrivateKey          privateKey    = (RSAPrivateKey) keyFactory1.generatePrivate(keySpec1);

        byte[]             buffer2     = Base64.getDecoder().decode(publicKeyString);
        KeyFactory         keyFactory2 = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec keySpec2      = new X509EncodedKeySpec(buffer2); // Fix 2: Apply X509EncodedKeySpec for the import of the public key
        PublicKey          publicKey   = (RSAPublicKey) keyFactory2.generatePublic(keySpec2);

        Cipher encryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // Fix 3: Specify algorithm and padding when instantiating the Cipher object
        encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);

        byte[] secretMessageBytes    = secretMessage.getBytes(StandardCharsets.UTF_8);
        byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessageBytes);
        String encodedMessage        = Base64.getEncoder().encodeToString(encryptedMessageBytes);

        Cipher decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // Fix 3: Specify algorithm and padding when instantiating the Cipher object
        decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);

        byte[] decryptedMessageBytes = decryptCipher.doFinal(encryptedMessageBytes);
        String decryptedMessage      = new String(decryptedMessageBytes, StandardCharsets.UTF_8);

        System.out.println("Step 1" + secretMessage);
        System.out.println("Step 2" + encodedMessage);
        System.out.println("Step 3" + decryptedMessage);
    }
}

With these changes, encryption and decryption work.通过这些更改,加密和解密工作。

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

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