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

JavaRSA BadPadding异常

施自怡
2023-03-14

我试图与客户机和服务器进行Diffie-Hellman密钥交换,但由于某种原因,当我解密发送到服务器的消息时。我得到以下例外:

Unable to decrypt ciphertext. -> Decryption error
javax.crypto.BadPaddingException: Decryption error
    at java.base/sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:378)
    at java.base/sun.security.rsa.RSAPadding.unpad(RSAPadding.java:290)
    at java.base/com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:359)
    at java.base/com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:392)
    at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2205)
    at server.Server.decrypt(Server.java:354)
    at server.Server.performDHKEX(Server.java:242)
    at server.Server.<init>(Server.java:145)
    at server.Driver.main(Driver.java:15)

我知道我的加密/解密方法工作得很好,因为如果我这样做:decrypt(encrypt(bytes)),不会引发异常。有人知道为什么会这样吗?下面是我的客户端和服务器代码。

蒂娅!

客户

private SecretKey performDHKEX()
    {   
        SecretKey sharedKey = null;
        
        try
        {
            // Send a message telling the server to get ready for a DH-KEX.
            outputStream.writeObject("DO_DH_KEX");
            
            KeyAgreement ecdhKex = KeyAgreement.getInstance("ECDH");
            KeyPairGenerator gen = KeyPairGenerator.getInstance("EC");
            KeyPair keyPair = gen.genKeyPair();
            
            // Send the Client's Public Value.
            byte[] cText = encrypt(keyPair.getPublic().getEncoded());
            decrypt(encrypt(keyPair.getPublic().getEncoded()));
            byte[] sign = sign(keyPair.getPublic().getEncoded());
            outputStream.writeObject(cText);
            outputStream.writeObject(X509_CERTIFICATE);
            
            
            // Start the exchange with Private Key.
            ecdhKex.init(keyPair.getPrivate());
            
            /* Wait for the response from the Server, then decrypt and load the
            public value the Server sent. */
            byte[][] recvCipherText = (byte[][]) inputStream.readObject();  
            X509Certificate serverCert = (X509Certificate) inputStream
                    .readObject();
            byte[] plainText = decrypt(recvCipherText[0]);
            
            // If the signature verifies, build a keyspec from the public value.
            if (verify(recvCipherText[1], plainText, serverCert))
            {
                // Create a new PublicKey from the Server's Public Value.
                PublicKey pub = KeyFactory.getInstance("EC")
                        .generatePublic(new X509EncodedKeySpec(plainText));
               
                // Perform the last step of the KEX and create a new SecretKey.
                ecdhKex.doPhase(pub, true);
                
                // Use the first 16 bytes of the generate secret for a key.
                sharedKey = new SecretKeySpec(Arrays.copyOfRange(ecdhKex
                        .generateSecret(), 0, 16), "AES");
            }
            else
                System.err.println("Error verifying signature.");
            
        } catch (IOException | ClassNotFoundException | IllegalStateException | 
                InvalidKeyException | NoSuchAlgorithmException | 
                InvalidKeySpecException ex)
        {
            System.err.println("Error during DH-KEX -> " + ex.getMessage());
        }
        
        System.out.println(Base64.getEncoder().encodeToString(sharedKey.getEncoded()));
        return sharedKey;
    }

服务器

private SecretKey performDHKEX()
    {      
        SecretKey sharedKey = null;
        
        try
        {
            KeyAgreement ecdhKex = KeyAgreement.getInstance("ECDH");
            KeyPairGenerator gen = KeyPairGenerator.getInstance("EC");
            KeyPair keyPair = gen.genKeyPair();
            
            byte[] recvMessage = (byte[]) inputStream.readObject();
            X509Certificate clientCert = (X509Certificate) inputStream
                    .readObject();
            
            // Decrypt the ciphertext.
            byte[] plainText = decrypt(recvMessage); // EXCEPTION THROWN HERE
             
            // If the signature and certificate verify, complete the KEX.
            if (verify(recvMessage, plainText, clientCert))
            {
                System.out.println("inside verify");
                // Send the Server's Public Value.
                byte[] sign = sign(keyPair.getPublic().getEncoded());
                byte[] cText = encrypt(keyPair.getPublic().getEncoded());  
                byte[][] sendArray = {cText, sign};
                outputStream.writeObject(sendArray);
                outputStream.writeObject(X509_CERTIFICATE);
                
                PublicKey pub = KeyFactory.getInstance("EC")
                        .generatePublic(new X509EncodedKeySpec(plainText));
                
                // Start the exchange with the server's Private Value and then
                // doPhase with the Client's public Value.
                ecdhKex.init(keyPair.getPrivate());
                ecdhKex.doPhase(pub, true);
                
                // Use the first 16 bytes of the generate secret for a key.
                sharedKey = new SecretKeySpec(Arrays.copyOfRange(ecdhKex
                        .generateSecret(), 0, 16), "AES");
            }
            
        } catch (IOException | ClassNotFoundException | IllegalStateException | 
                InvalidKeyException | NoSuchAlgorithmException | 
                InvalidKeySpecException ex)
        {
            System.err.println("Error during DH-KEX -> " + ex.getMessage());
        }
        
        System.out.println(Base64.getEncoder().encodeToString(sharedKey.getEncoded()));
        
        return sharedKey;
    }

加密

 private byte[] encrypt(byte[] message)
    {
        byte[] cipherText = null;
        
        try
        {
            rsaCipher.init(Cipher.ENCRYPT_MODE, PRIV_KEY);
            cipherText = rsaCipher.doFinal(message);
        } catch (InvalidKeyException | BadPaddingException | 
                IllegalBlockSizeException ex)
        {
            System.err.println("Error encrypting message. -> " + ex
                    .getMessage());
            ex.printStackTrace();
        }
        
        return cipherText;
    }

解密

private byte[] decrypt(byte[] cipherText)
    {
        try
        {
            rsaCipher.init(Cipher.DECRYPT_MODE, PUB_KEY);
            return rsaCipher.doFinal(cipherText);
        } catch (InvalidKeyException | IllegalBlockSizeException | 
                BadPaddingException ex)
        {
            System.err.println("Unable to decrypt ciphertext. -> " + ex
                    .getMessage());
            ex.printStackTrace();
        }
        
        return null;
    }

为了澄清,RSA密码是RSA/ECB/PKCS1Padding,PRIV_KEY/PUB_KEY是从KeyTool生成的

共有1个答案

洪高扬
2023-03-14

当使用错误的密钥执行解密时,异常是一种非常常见的失败模式。

服务器必须使用客户端的公钥进行解码,同时使用自己的密钥进行编码。

同样,客户端必须使用服务器的公钥进行解码,并使用自己的密钥进行编码。

您执行的测试表明解码和编码使用的是本地公钥,而不是发送方的公钥。

 类似资料:
  • 应用程序通常会通过抛出另一个异常来响应异常。 实际上,第一个异常引起第二个异常。 它可以是非常有助于用户知道什么时候一个异常导致另一个异常。 “异常链(Chained Exceptions)”帮助程序员做到这一点。 以下是Throwable中支持异常链的方法和构造函数。 Throwable getCause() Throwable initCause(Throwable) Throwable(St

  • 你可以使用raise语句 引发 异常。你还得指明错误/异常的名称和伴随异常 触发的 异常对象。你可以引发的错误或异常应该分别是一个Error或Exception类的直接或间接导出类。 如何引发异常 例13.2 如何引发异常 #!/usr/bin/python # Filename: raising.py classShortInputException(Exception):     '''A u

  • 问题内容: 异常存储在哪里?堆,堆。如何为异常分配和释放内存?现在,如果您有多个需要处理的异常,是否创建了所有这些异常的对象? 问题答案: 我假设为异常分配的内存分配方式与所有其他对象(在堆上)分配方式相同。 这曾经是个问题,因为您不能为OutOfMemoryError分配内存,这就是直到Java 1.6之前 才没有堆栈跟踪的原因。现在,它们也为stacktrace预分配了空间。 如果您想知道在抛

  • 异常Exception 以传统的try,catch抓取异常 如果在业务层不catch,框架层会捕捉,并返回一个500的server error响应。 如果在开发环境会返回一个500的具体错误的trace响应。 try { throw new \Exception("Error Processing Request", 1); //yield throwExc

  • 因为Java编程语言不需要捕获方法或声明未检查异常(包括 RuntimeException、Error及其子类),程序员可能会试图编写只抛出未检查异常的代码,或使所有异常子类继承自RuntimeException。这两个快捷方式都允许程序员编写代码,而不必担心编译器错误,也不用担心声明或捕获任何异常。虽然这对于程序员似乎很方便,但它避开了捕获或者声明异常的需求,并且可能会导致其他人在使用您的类而产

  • 当面对选择抛出异常的类型时,您可以使用由别人编写的异常 - Java平台提供了许多可以使用的异常类 - 或者您可以编写自己的异常类。 如果您对任何以下问题回答“是”,您应该编写自己的异常类;否则,你可以使用别人的。 你需要一个Java平台中没有表示的异常类型吗? 如果用户能够区分你的异常与由其他供应商编写的类抛出的异常吗? 你的代码是否抛出不止一个相关的异常? 如果您使用他人的例外,用户是否可以访

  • 异常 对于异常处理,倾向使用 raise 而不是 fail。 # 差 fail SomeException, 'message' # 好 raise SomeException, 'message' 不要在带双参数形式的 raise 方法中显式指定 RuntimeError。 # 差 raise RuntimeError, 'message' # 好 - 默认就是 RuntimeError rai

  • 在Java语言中,是使用“异常(exception)”来处理错误及其他异常事件。术语“异常”是短语“异常事件(exceptional event)”的缩写。 异常是在程序执行期间发生的事件,它会中断程序指令的正常流程。 当在方法中发生错误时,该方法创建一个对象并将其移交给运行时系统。 该对象称为“异常对象(exception object)”,包含有关错误的信息,包括错误发生时其类型和程序的状态。