【问题标题】:java bouncy castle RSA 4096 decryption padding errorjava充气城堡RSA 4096解密填充错误
【发布时间】:2017-08-21 06:54:38
【问题描述】:

在用公钥 rsa 4096 加密后,我已经尝试了两天来解密包含“lolilol”的私钥的文件。然后我得到填充错误,我尝试了一切,我得到了错误@ 987654321@.

即使在阅读了关于填充的文档后,我也没有成功:加密工作正常,但解密包含错误。

这是我的代码:

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;

import javax.crypto.Cipher;

import sun.misc.BASE64Encoder;

public class GenerateRSAKeys{


    private Key pubKey;
    private Key privKey;

    public static void main(String[] args)
    {
        String input = "C:\\Users\\toto\\Desktop\\nomFichier_entrant.ext";
        String output = "C:\\Users\\toto\\Desktop\\nomFichier_entrant.ext.enc";
        String dec = "C:\\Users\\toto\\Desktop\\nomFichier_entrant.ext.dec";
        String publicKeyFilename = "C:\\Users\\toto\\Desktop\\HR_pubkey_prd.pem";
        String privateKeyFilename = "C:\\Users\\toto\\Desktop\\PE_privkey_prd.pem";

        GenerateRSAKeys generateRSAKeys = new GenerateRSAKeys();

        /*         if (args.length < 2)
        {
            System.err.println("Usage: java "+ generateRSAKeys.getClass().getName()+
            " Public_Key_Filename Private_Key_Filename");
            System.exit(1);
        }

        publicKeyFilename = args[0].trim();
        privateKeyFilename = args[1].trim(); */
        generateRSAKeys.generate(publicKeyFilename, privateKeyFilename);

        //generateRSAKeys.encrypt(input, output);
        generateRSAKeys.encrypt(input, output);
        generateRSAKeys.decrypt(output, dec);

    }

    private void generate (String publicKeyFilename, String privateFilename){

        try {

            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

            // Create the public and private keys
            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");
            BASE64Encoder b64 = new BASE64Encoder();

            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
            /* SecureRandom random = new SecureRandom();

            keyGen.initialize(4096, random);

            KeyPair pair = keyGen.generateKeyPair();
            pubKey = pair.getPublic();
            privKey = pair.getPrivate(); */

            SecureRandom random = createFixedRandom();
            generator.initialize(4096, random);

            KeyPair pair = generator.generateKeyPair();
            pubKey = pair.getPublic();
            privKey = pair.getPrivate();

            System.out.println("publicKey : " + b64.encode(pubKey.getEncoded()));
            System.out.println("privateKey : " + b64.encode(privKey.getEncoded()));

            BufferedWriter out = new BufferedWriter(new FileWriter(publicKeyFilename));
            out.write(b64.encode(pubKey.getEncoded()));
            out.close();

            out = new BufferedWriter(new FileWriter(privateFilename));
            out.write(b64.encode(privKey.getEncoded()));
            out.close();


        }
        catch (Exception e) {
            System.out.println(e);
        }
    }

    public static SecureRandom createFixedRandom()
    {
        return new FixedRand();
    }

    private static class FixedRand extends SecureRandom {

        MessageDigest sha;
        byte[] state;

        FixedRand() {
            try
            {
                this.sha = MessageDigest.getInstance("SHA-1");
                this.state = sha.digest();
            }
            catch (NoSuchAlgorithmException e)
            {
                throw new RuntimeException("can't find SHA-1!");
            }
        }

        public void nextBytes(byte[] bytes){

            int    off = 0;

            sha.update(state);

            while (off < bytes.length)
            {                
                state = sha.digest();

                if (bytes.length - off > state.length)
                {
                    System.arraycopy(state, 0, bytes, off, state.length);
                }
                else
                {
                    System.arraycopy(state, 0, bytes, off, bytes.length - off);
                }

                off += state.length;

                sha.update(state);
            }
        }
    }

    public void encrypt(String input, String output) {
        File outputFile;
        FileInputStream inputStream;
        FileOutputStream outputStream;
        Cipher cipher;
        byte[] inputBytes;
        byte[] outputBytes;

        try {
            outputFile = new File(output);
            inputStream = new FileInputStream(input);
            outputStream = new FileOutputStream(outputFile);
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            inputBytes = new byte[(int) input.length()];
            inputStream.read(inputBytes);
            outputBytes = cipher.doFinal(inputBytes);
            outputStream.write(outputBytes);

            // System.out.println(new String(inputBytes, "UTF-8"));

            System.out.println("encrypt");
            System.out.println(new String(outputBytes, "UTF-8"));
            System.out.println("fin encrypt");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void decrypt(String input, String output) {
        File outputFile;
        FileInputStream inputStream;
        FileOutputStream outputStream;
        Cipher cipher;
        byte[] inputBytes;
        byte[] outputBytes;

        try {
            outputFile = new File(output);
            inputStream = new FileInputStream(input);
            outputStream = new FileOutputStream(outputFile);
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privKey);
            inputBytes = new byte[(int) input.length()];
            inputStream.read(inputBytes);
            outputBytes = cipher.doFinal(inputBytes);
            outputStream.write(outputBytes);

            // System.out.println(new String(inputBytes, "UTF-8"));

            System.out.println("decrypt");
            System.out.println(new String(outputBytes, "UTF-8"));
            System.out.println("fin decrypt");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

【问题讨论】:

  • 你怎么知道加密工作正常?也许它已损坏?
  • 这是真的。只是使用以下代码创建的新文件:èBÓ| ¦Î´G¹DÅÄ¢LŬÐßqÍ nüÈú¹;Ú‹nšÇfó§½Bö‡Û6XRw}¿¹:Q,è¼Q-!ÜóŠÇöïv ¨ò'øa}ŽÁãúcÝøcF^dÆé}ÚÛÝö'×>ËÍqz«V®¥Öôt÷ã¥WŒpƒ …9O,nZeBÔ Þ*ðü4i3úm÷Îu)Æ1¨‰±±{&!qÁëT~¼â5 $ѼøòÛ¡¯ xìç|t¾„¥ Çb¼(ãæ"á/~á2gVâUkŠXaóXôÄáúÇ,™$p ZÚªí;8›ô>çp•œQHCˆ”‡ÊRû©ošC‰Tļ²ÑÔvˆ«A"õ"íwÏs'~(ã{§îÛ R ‹ÿj:óŒKÌ w®?V¹Ô Q°Œ¯éÆÎ¦ÔéÚ¥{óË>¬÷z‹dÈtýÍ6w¾åýA–
  • 但是你怎么知道这是应该的,也许这是错误的
  • 它仍然无法在 java 上运行,我已经在 linux 上对其进行了测试,它可以在 linux 上使用以下命令:openssl rsautl -decrypt -inkey privkey.pem -in $file.key.enc -出 $file.ext.key.dec。我在解密文件 $file.ext.key.dec 后使用以下命令解密文件加密:file.ext.enc:openssl enc -d -aes-256-cbc -kfile $file.ext.key.dec -在 $file.ext.enc -out $file.ext
  • 可能是加载私钥有问题。我仍在寻找解决方案。

标签: java encryption file-io rsa padding


【解决方案1】:

您的代码中有多个问题:

  • 您永远不会关闭文件流。如果您不这样做,则可能实际上没有写入任何数据。如果密文没有(完全)写入,那么解密显然会失败。

  • FileInputStream 无法准确衡量基础文件包含多少数据。为此,您必须使用 File 类:

    File inputFile = new File(input);
    FileInputStream inputStream = new FileInputStream(inputFile);
    FileOutputStream outputStream = new FileOutputStream(output);
    byte[] inputBytes = new byte[(int) inputFile.length()];
    
  • 当您阅读文件内容时,您必须始终检查您阅读了多少并准确使用了该数量:

    int readBytes = inputStream.read(inputBytes);
    byte[] outputBytes = cipher.doFinal(inputBytes, 0, readBytes);
    
  • 始终使用完全限定的密码字符串。 Cipher.getInstance("RSA"); 可能会产生不同的密码,具体取决于默认的安全提供程序。在 OpenJDK 中,它默认为 Cipher.getInstance("RSA/ECB/PKCS1Padding");。现在,您应该使用 OAEP 而不是默认的 PKCS#1 v1.5 填充。所以你可能应该使用Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");。

以下是这两种方法的完整代码:

public void encrypt(String input, String output) {
    File inputFile;
    FileInputStream inputStream;
    FileOutputStream outputStream;
    Cipher cipher;
    byte[] inputBytes;
    byte[] outputBytes;

    try {
        System.out.println("encrypt");

        cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);

        inputFile = new File(input);
        inputStream = new FileInputStream(inputFile);
        outputStream = new FileOutputStream(output);
        inputBytes = new byte[(int) input.length()];
        int readBytes = inputStream.read(inputBytes);
        outputBytes = cipher.doFinal(inputBytes, 0, readBytes);
        outputStream.write(outputBytes);

        System.out.println("fin encrypt");

        inputStream.close();
        outputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void decrypt(String input, String output) {
    File inputFile;
    FileInputStream inputStream;
    FileOutputStream outputStream;
    Cipher cipher;
    byte[] inputBytes;
    byte[] outputBytes;

    try {
        System.out.println("decrypt");

        cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privKey);

        inputFile = new File(input);
        inputStream = new FileInputStream(inputFile);
        outputStream = new FileOutputStream(output);
        inputBytes = new byte[(int) inputFile.length()];
        int readBytes = inputStream.read(inputBytes);
        outputBytes = cipher.doFinal(inputBytes, 0, readBytes);
        outputStream.write(outputBytes);

        System.out.println("Decryption result: " + new String(outputBytes, "UTF-8"));
        System.out.println("fin decrypt");

        inputStream.close();
        outputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

【讨论】:

  • B:非常感谢。它适用于我的文件测试。我要去看看水獭。
  • 看来你还是有问题。我已经运行它并且它按预期工作。见the full class。我已经注释了一些不必要的行并删除了“BC”标志。
  • 嗨 Artjom B,事实上,我有一个使用公钥加密文件的客户端。在我的应用程序中,我只需要解密,而不是加密。我用私钥解密,那是我得到填充错误的时候。也许问题来自随机性。
  • javax.crypto.BadPaddingException: sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:380) 在 sun.security.rsa.RSAPadding.unpad(RSAPadding.java:291) 的解密错误在 com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:365) 在 com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:391) 在 javax.crypto.Cipher.doFinal(Cipher.java :2189) 在 deciphertodeploy.Test24RsaFileIO.decrypt(Test24RsaFileIO.java:168) 在 deciphertodeploy.Test24RsaFileIO.main(Test24RsaFileIO.java:39)
  • 我明白了。因此,您必须解码相应的私钥。这不是您当前问题的一部分,如果您编辑您的问题以包含它,它会变得一团糟。请就该问题提出一个新问题。我已经用工作代码回答了你当前的问题。
猜你喜欢
  • 2014-09-19
  • 1970-01-01
  • 2013-05-25
  • 1970-01-01
  • 2016-08-10
  • 2013-04-20
  • 2015-08-09
  • 2014-05-23
  • 1970-01-01
相关资源
最近更新 更多