java.security.NoSuchAlgorithmException:RSA 签名不可用

2022-01-10 00:00:00 cryptography rsa digital-signature java

这是个例外

<上一页>线程主"java.security.NoSuchAlgorithmException 中的异常:RSA 签名不可用在 java.security.Signature.getInstance(Signature.java:229)在 MailClient.main(MailClient.java:52)

这是我的代码

import java.io.*;导入java.net.*;导入 java.nio.ByteBuffer;导入 java.util.*;导入java.security.*;公共类 MailClient {公共字符串 getMessage(邮件 m){返回 m.message;}公共静态 void main(String[] args) 抛出异常 {//初始化BufferedReader br = new BufferedReader(new InputStreamReader(System.in));字符串主机 = args[0];int 端口 = Integer.parseInt(args[1]);字符串用户 ID = args[2];而(真){//连接到服务器套接字 s = 新套接字(主机,端口);DataInputStream dis = new DataInputStream(s.getInputStream());DataOutputStream dos = new DataOutputStream(s.getOutputStream());ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());oos.flush();ObjectInputStream ois = new ObjectInputStream(s.getInputStream());//待办事项:登录//这两行只是为了让提供的程序运行而不会崩溃.//你可能想改变它们,当然在它们之后添加东西dos.writeUTF(userid);字符串 userPrivateKeyFileName = 用户 ID + ".prv";//获取创建签名的密钥ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(userPrivateKeyFileName));PrivateKey privateKey = (PrivateKey)keyIn.readObject();keyIn.close();//创建时间戳和随机数long t1 = (new Date()).getTime();双 q1 = Math.random();//ByteBuffer 稍后转换为字节ByteBuffer bb = ByteBuffer.allocate(16);bb.putLong(t1);bb.putDouble(q1);//创建签名,使用时间戳和随机数作为数据签名 sig = Signature.getInstance("RSA");sig.initSign(privateKey);sig.update(bb.array());字节[] 签名 = sig.sign();//发送数据和签名DataOutputStream out = new DataOutputStream(s.getOutputStream());out.writeUTF(userid);out.writeLong(t1);out.writeDouble(q1);out.writeInt(signature.length);out.write(签名);out.flush();布尔答案 = dis.readBoolean();//通过了验证登录如果(回答){//接收多少条消息int numMsg = dis.readInt();System.out.println("你有 " + numMsg + " 收到的消息.");//TO DO:阅读消息ArrayList<邮件>msg = new ArrayList<>(numMsg);for(int i=0;i) ois.readObject();}而(!msg.isEmpty()){//对于每封邮件,显示发件人、时间戳、消息System.out.println(msg.get(0).sender);System.out.println(msg.get(0).timestamp);System.out.println(msg.get(0).message);MessageDigest md = MessageDigest.getInstance("SHA-1");md.update(msg.get(0).hashcash);字节[] 摘要 = md.digest();boolean normalMail = msg.get(0).checkHashcash(digest);如果(正常邮件){//检查每封邮件是否为原始邮件未被修改//接收邮件System.out.println(msg.get(0).message);}else{System.out.println("这是垃圾邮件");System.out.println(msg.get(0).message);}msg.remove(0);}//发送信息System.out.println("您要发送消息[Y/N]?");String wantToSend = br.readLine();如果(!wantToSend.equals(Y")){dos.writeBoolean(false);返回 ;}dos.writeBoolean(true);System.out.println("请输入收件人的用户名:");字符串接收者 = br.readLine();System.out.println("请输入您的信息:");字符串消息 = br.readLine();//TO DO:发送邮件邮件 m = 新邮件(用户 ID、收件人、邮件);MessageDigest md = MessageDigest.getInstance("SHA-1");md.update(m.hashcash);字节[] 摘要 = md.digest();而(m.checkHashcash(摘要)){m.setHashcash(摘要);}out.write(摘要);out.flush();//发送时间戳和摘要到服务器长邮件时间戳 = m.timestamp.getTime();out.writeLong(mailTimestamp);oos.writeObject(m);}}}}

解决方案

如果你运行下面的代码,你会得到一个你的Java安装支持的签名算法列表.

TreeSet算法=新树集<>();对于(提供者提供者:Security.getProviders())对于(服务服务:provider.getServices())if (service.getType().equals("签名"))算法.add(service.getAlgorithm());对于(字符串算法:算法)System.out.println(算法);

当我运行它(Windows,Java 1.8.0_65)时,我得到:

MD2withRSAMD5 和 SHA1 和 RSA带有 RSA 的 MD5NONEwithDSANONEwithECDSANONEwithRSA带有 DSA 的 SHA1SHA1 和 ECDSASHA1withRSASHA224 和 DSASHA224 和 ECDSASHA224 和 RSA带有 DSA 的 SHA256SHA256 和 ECDSASHA256 和 RSASHA3​​84 和 ECDSASHA3​​84 和 RSASHA512 和 ECDSASHA512 和 RSA

如您所见,RSA 不是有效的签名算法.
也许 NONEwithRSA 是你所追求的?

this is exception

Exception in thread "main" java.security.NoSuchAlgorithmException: RSA Signature not available
    at java.security.Signature.getInstance(Signature.java:229)
    at MailClient.main(MailClient.java:52)

this is my code

import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.util.*;
import java.security.*;

public class MailClient {

    public String getMessage(Mail m){
        return m.message;
    }

    public static void main(String[] args) throws Exception {

        // Initialisation
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        String host = args[0];
        int port = Integer.parseInt(args[1]);
        String userid = args[2];

        while(true) {
            // connect to server
            Socket s = new Socket(host,port);
            DataInputStream dis = new DataInputStream(s.getInputStream());
            DataOutputStream dos = new DataOutputStream(s.getOutputStream());
            ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
            oos.flush();
            ObjectInputStream ois = new ObjectInputStream(s.getInputStream());

            // TO DO: login

            // these two lines are here just to make the supplied programs run without crashing.
            // You may want to change them, and certainly add things after them
            dos.writeUTF(userid);

            String userPrivateKeyFileName = userid + ".prv";
            // Get the key to create the signature
            ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(userPrivateKeyFileName));
            PrivateKey privateKey = (PrivateKey)keyIn.readObject();
            keyIn.close();

            // create timeStamp and random number
            long t1 = (new Date()).getTime();
            double q1 = Math.random();
            // ByteBuffer to convert to bytes later
            ByteBuffer bb = ByteBuffer.allocate(16);
            bb.putLong(t1);
            bb.putDouble(q1);

            // create signature, using timeStamp and random number as data
            Signature sig = Signature.getInstance("RSA");
            sig.initSign(privateKey);
            sig.update(bb.array());
            byte[] signature = sig.sign();

            // send data and signature
            DataOutputStream out = new DataOutputStream(s.getOutputStream());
            out.writeUTF(userid);
            out.writeLong(t1);
            out.writeDouble(q1);
            out.writeInt(signature.length);
            out.write(signature);
            out.flush();

            boolean answer = dis.readBoolean();

            //passed the verifyLogin
            if (answer)
                {
                // receive how many messages
                int numMsg = dis.readInt();
                System.out.println("You have " + numMsg + " incoming messages.");

                // TO DO: read messages
                ArrayList<Mail> msg = new ArrayList<>(numMsg);
                for(int i=0;i<numMsg;i++){
                    //@Unchecked
                    msg = (ArrayList<Mail>) ois.readObject();
                }
                while(!msg.isEmpty()){
                    //for each mail, display sender,timestamp,message
                    System.out.println(msg.get(0).sender);
                    System.out.println(msg.get(0).timestamp);
                    System.out.println(msg.get(0).message);
                    MessageDigest md = MessageDigest.getInstance("SHA-1");
                    md.update(msg.get(0).hashcash);

                    byte[] digest = md.digest();
                    boolean normalMail = msg.get(0).checkHashcash(digest);
                    if(normalMail){
                    //check each mail is original that it isn't modified
                    //receive mail
                        System.out.println(msg.get(0).message);
                        }
                    else{System.out.println("it's a spam message.");
                        System.out.println(msg.get(0).message);
                        }
                    msg.remove(0);
                }


                // send messages
                System.out.println("Do you want to send a message [Y/N]?");
                String wantToSend = br.readLine();
                if (!wantToSend.equals("Y")) {
                    dos.writeBoolean(false);
                    return ;
                }
                dos.writeBoolean(true);

                System.out.println("Enter userid of recipient:");
                String recipient = br.readLine();
                System.out.println("Type your message:");
                String message = br.readLine();

                // TO DO: send mail
                Mail m = new Mail(userid, recipient, message);
                MessageDigest md = MessageDigest.getInstance("SHA-1");
                md.update(m.hashcash);

                byte[] digest = md.digest();
                while(m.checkHashcash(digest)){
                    m.setHashcash(digest);

                }

                out.write(digest);
                out.flush();
                // send timeStamp and digest to server
                long mailTimestamp = m.timestamp.getTime();
                out.writeLong(mailTimestamp);




                oos.writeObject(m);

                }
            }


    }

}

解决方案

If you run the following code, you will get a list of signature algorithms supported by your Java installation.

TreeSet<String> algorithms = new TreeSet<>();
for (Provider provider : Security.getProviders())
    for (Service service : provider.getServices())
        if (service.getType().equals("Signature"))
            algorithms.add(service.getAlgorithm());
for (String algorithm : algorithms)
    System.out.println(algorithm);

When I run it (Windows, Java 1.8.0_65), I get:

MD2withRSA
MD5andSHA1withRSA
MD5withRSA
NONEwithDSA
NONEwithECDSA
NONEwithRSA
SHA1withDSA
SHA1withECDSA
SHA1withRSA
SHA224withDSA
SHA224withECDSA
SHA224withRSA
SHA256withDSA
SHA256withECDSA
SHA256withRSA
SHA384withECDSA
SHA384withRSA
SHA512withECDSA
SHA512withRSA

As you can see, RSA is not a valid signature algorithm.
Maybe NONEwithRSA is what you're after?

相关文章