代码之家  ›  专栏  ›  技术社区  ›  PatPanda

Java:RSA加密问题

  •  0
  • PatPanda  · 技术社区  · 3 年前

    关于RSA的Java代码的小问题。

    我有一段非常简单的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);
        }
        
    }
    
    

    我本以为这会奏效,并且能够看到“第二步”中的一些胡言乱语

    但相反,我看到的是:

    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)
    

    请问这段代码出了什么问题?

    非常感谢。

    0 回复  |  直到 3 年前
        1
  •  1
  •   Topaco    3 年前

    代码中存在以下问题:

    • 将导入专用和公用EC密钥(此外,还将交换这两个密钥)。由于要执行RSA加密,因此要使用RSA密钥。
    • 使用导入公钥 PKCS8EncodedKeySpec 然而 PKCS8EncodedKeySpec 用于导入专用PKCS#8密钥。由于要导入公共X.509/SPKI密钥, X509EncodedKeySpec 必须使用。
    • 当实例化 Cipher 对象,只指定算法( RSA ),但不是填充。因此,将使用依赖于提供程序的默认值进行填充。为了避免无意中使用不正确的填充和跨平台问题,还应明确指定填充(例如。 RSA/ECB/PKCS1Padding )。

    固定代码如下:

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

    有了这些变化,加密和解密就可以工作了。