Java笔记-加密应用在网络通信中的使用

逻辑是这样的:

 

逻辑解释:

1.OpenSSL生成RSA私钥和公钥,公钥存客户端,私钥存服务端;

2.客户端与服务端的DH分别生成自己的公钥和私钥,并且使用相同的公钥和私钥算法;

3.首先客户端把DH生成的公钥使用RSA加密,通过HTTP协议,发送到服务端,服务端把先解密RSA,然后把自己DH模块的公钥发给客户端;

4.客户端和服务端都拿到了对方的公钥,再与自己的私钥,通过密钥公式,算出AES加密密钥。后面发送数据时都通过AES加密。

程序运行截图如下:

 

关键源码如下:

服务端(IDEA普通Java项目):

Main.java

package cn.it1995;

import cn.it1995.http.HttpCallback;
import cn.it1995.http.HttpServer;
import cn.it1995.tool.AES;
import cn.it1995.tool.DH;
import cn.it1995.tool.DataSecret;
import cn.it1995.tool.RSA;

import java.io.UnsupportedEncodingException;
import java.util.Map;

public class Main {

    private static final String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjuN97tkBc0QcKGU9oXydaQN7q" +
            "wZnThxTOmdIc8O1yuA9FrDZpZ3Sz908vTqM/YPZkOUaYrGwsBO7FeQovoX7nQPKu" +
            "YQpRDqt7OKzhwPavyynH0Jz38PDyCBw45zwl4Ux8BtsggTrGVxAqNjO4KkuyL1QS" +
            "8amn4Fzl1CBre8Y0gQIDAQAB";

    private static final String PRI_KEY = "MIICdAIBADANBgkqhkiG9w0BAQEFAASCAl4wggJaAgEAAoGBAKO433u2QFzRBwoZ" +
            "T2hfJ1pA3urBmdOHFM6Z0hzw7XK4D0WsNmlndLP3Ty9Ooz9g9mQ5RpisbCwE7sV5" +
            "Ci+hfudA8q5hClEOq3s4rOHA9q/LKcfQnPfw8PIIHDjnPCXhTHwG2yCBOsZXECo2" +
            "M7gqS7IvVBLxqafgXOXUIGt7xjSBAgMBAAECgYAgp0uzcdsOaAY+ZmPnDitcHdoX" +
            "+jsC7EsjFZzJduf03G73V2yWwzKMfkPFzKpUhrM9tAq3gpQkh2tT6Vs1usEDbrDd" +
            "e08Cc3D5YWK7HuTfO3kkJTSNOK0JfuT1UQaTjCmDQWWjPmYbu6UN0UDv4Mo26dgl" +
            "cp9h0wlaPsSFN3O97QJBANgj+4i7ABAdbTuUfq6Tcr38E7wYSFTUeL5jTd4sO636" +
            "+KJ6zx4uTXAmxnt9OdIY1ihLRqDh8VbiorqOelGf6iMCQQDB6jZver3mTMe6ntSY" +
            "hx3JWOCDM3ULkPvOWGrAcRsNKjyIuo37taXa7fuqmVQQq9MJYikJfilMhkgwkV/X" +
            "ihcLAkBsOvBskj9A0ottJzmcT4dIbR6wtHQbzl078NwAIaQsxZyVN+vY0BTE0RXY" +
            "pmc6tmcevDr8uscv28Liqg/EKdCDAkAjL9C44djblUsYvgFtu/bXtlzm8ctnUeOf" +
            "ScP1L5DtDqD1XoStDAUQeOaVykTK0aL1rO4tXss3q5Yl2fs+LTyJAj8f7N5kzw08" +
            "9S5OWCHoEm5UOeAvjFh//cjXi6lyqetBW3w17muZ2OumUAbKJXksyzmT6/QRpkX3" +
            "S0w/tqdJXLs=";

    private static final String HANDHAKE = "handshake";

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

//        String content = "123456";
//        String encrypted = RSA.encrypt(content, PUB_KEY);
//        System.out.println(encrypted);
//        System.out.println(RSA.decrypt(encrypted, PRI_KEY));

        //查密钥
//        DH dhC = new DH();
//        DH dhS = new DH();
//
//        int publicKeyC = dhC.getPublicKey();
//        int publicKeyS = dhS.getPublicKey();
//
//        byte[] secretC = dhC.getSecretKey(publicKeyS);
//        byte[] secretS = dhS.getSecretKey(publicKeyC);
//
//        System.out.println("client's secrete is : ");
//        for(byte i : secretC){
//
//            System.out.print(i + " ");
//        }
//        System.out.println("\nserver's secrete is : ");
//        for(byte i : secretS){
//
//            System.out.print(i + " ");
//        }


//        AES aes = new AES();
//        byte[] encrypted = aes.encrypt(content);
//        System.out.println(new String(encrypted));
//        byte[] decrypt = aes.decrypt(encrypted);
//        System.out.println(new String(decrypt));
//
        System.out.println("start http server");
        HttpServer server = new HttpServer(new HttpCallback() {

            private DH mDh = new DH();
            private AES mAes = new AES();

            @Override
            public byte[] onResponse(String request) {

                if(isHandshake(request)){

                    //握手
                    Map<String, String> header = HttpServer.getHeader(request);
                    String handshake = header.get(HANDHAKE);
                    System.out.println("Handshake为:" + handshake);
                    int dhPubKey = Integer.valueOf(RSA.decrypt(handshake, PRI_KEY));

                    //设置为AES密钥
                    mAes.setKey(mDh.getSecretKey(dhPubKey));
                    System.out.println("解密后,客户端dhPubKey:"  + dhPubKey);

                    return DataSecret.int2Byte(mDh.getPublicKey());
                }

                byte[] result = mAes.encrypt("Hello World");
                return result;
            }
        });

        server.startHttpServer();
    }

    private static boolean isHandshake(String request){

        return (request != null && request.contains(HANDHAKE));
    }


}

DH.java

package cn.it1995.tool;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

public class DH {

    private static final int dhP = 45;
    private static final  int dhG = 9;

    private int mPriKey;

    //构造函数随机私钥
    public DH(){

        Random r = new Random();
        mPriKey = r.nextInt(20);
        System.out.println("dh priKey is : " + mPriKey);
    }

    //公钥计算公式计算出公钥
    public int getPublicKey(){

        return (int) (Math.pow(dhG, mPriKey) % dhP);
    }

    //使用对方公钥与自己私钥生成密钥
    //在把结果转256字节,AES密钥需要128字节或256字节
    public byte[] getSecretKey(long publicKey){

        int buf = (int) (Math.pow(publicKey, mPriKey) % dhP);
        return sha256(buf);
    }

    //转换成byte[256]类型,作为AES密钥
    private byte[] sha256(int data){

        try {

            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(DataSecret.int2Byte(data));
            return messageDigest.digest();
        }
        catch (NoSuchAlgorithmException e) {
            
            e.printStackTrace();
        }

        return new byte[]{-1};
    }
}

HttpServer.java

package cn.it1995.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class HttpServer {

    private boolean mRunning;
    private HttpCallback mCallback;

    public HttpServer(HttpCallback Callback) {

        this.mCallback = Callback;
    }

    public void startHttpServer(){

        if(mRunning){

            return;
        }
        mRunning = true;

        try {

            ServerSocket serverSocket = new ServerSocket(80);
            while (mRunning){

                Socket accept = serverSocket.accept();
                ExecutorService threadPool = Executors.newCachedThreadPool();
                threadPool.execute(new HttpThread(accept, mCallback));
            }
        }
        catch (IOException e) {

            e.printStackTrace();
        }
    }

    public static Map<String, String> getHeader(String request){

        Map<String, String> header = new HashMap<>();
        BufferedReader reader = new BufferedReader(new StringReader(request));

        //逐行解析

        try{

            String line = reader.readLine();
            while (line != null && !line.trim().isEmpty()){

                int p = line.indexOf(":");
                if(p >= 0){

                    header.put(line.substring(0, p).trim().toLowerCase(),
                            line.substring(p + 1).trim());
                }
                line = reader.readLine();
            }
        }
        catch (Exception e){

            e.printStackTrace();
        }

        return header;
    }
}

HttpThread.java

package cn.it1995.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class HttpThread implements Runnable{

    private Socket mSocket;
    private HttpCallback mCallback;

    public HttpThread(Socket socket, HttpCallback httpCallback){

        mSocket = socket;
        mCallback = httpCallback;
    }

    @Override
    public void run() {

        try {

            BufferedReader reader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
            String content;
            StringBuffer request = new StringBuffer();

            while((content = reader.readLine()) != null
                    && !content.trim().isEmpty()){

                request.append(content).append("\n");
            }

            System.out.println("request:\n" + request);
            byte[] response = new byte[0];
            if(mCallback != null){

                response = mCallback.onResponse(request.toString());
            }

            String responseFirstLine = "HTTP/1.1 200 OK \r\n";
            String responseHead = "Content-type:" + "text/html" + "\r\n";
            OutputStream outputStream = mSocket.getOutputStream();
            outputStream.write(responseFirstLine.getBytes());
            outputStream.write(responseHead.getBytes());
            outputStream.write("\r\n".getBytes());
            outputStream.write(response);

            mSocket.close();
        }
        catch (IOException e) {

            e.printStackTrace();
        }
    }
}

客户端(Android项目):

MainActivity.java

package com.example.myclient;

import android.os.Bundle;

import com.example.myclient.http.HttpRequest;
import com.example.myclient.tool.AES;
import com.example.myclient.tool.DH;
import com.example.myclient.tool.RSA;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {

    private static final String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjuN97tkBc0QcKGU9oXydaQN7q" +
            "wZnThxTOmdIc8O1yuA9FrDZpZ3Sz908vTqM/YPZkOUaYrGwsBO7FeQovoX7nQPKu" +
            "YQpRDqt7OKzhwPavyynH0Jz38PDyCBw45zwl4Ux8BtsggTrGVxAqNjO4KkuyL1QS" +
            "8amn4Fzl1CBre8Y0gQIDAQAB";

    private static final String URL = "http://192.168.20.59/";
    private byte[] mAesKey;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        final HttpRequest request = new HttpRequest(URL);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {


            @Override
            public void onClick(View v) {

                if(mAesKey == null || mAesKey.length <= 0){

                    final DH dh = new DH();
                    int pubKey = dh.getPublicKey();
                    Log.d("test", "dh 公钥为:" + dh.getPublicKey());
                    try {
                        request.handshake(new Callback() {
                            @Override
                            public void onFailure(Call call, IOException e) {

                                Log.d("error", "onFailure: 握手失败");
                            }

                            @Override
                            public void onResponse(Call call, Response response) throws IOException {

                                byte[] pubKey = response.body().bytes();
                                mAesKey = dh.getSecretKey(pubKey);
                                Log.d("success", "success: 握手成功aes密钥为:" + new String(mAesKey));
                            }
                        }, RSA.encrypt(String.valueOf(pubKey), PUB_KEY));
                    }
                    catch (UnsupportedEncodingException e) {

                        e.printStackTrace();
                    }
                }
                else {

                    request.request(new Callback() {
                        @Override
                        public void onFailure(Call call, IOException e) {

                            Log.e("error", "请求失败");
                        }

                        @Override
                        public void onResponse(Call call, Response response) throws IOException {

                            byte[] bytes = response.body().bytes();
                            AES aes = new AES(mAesKey);
                            String content = new String(aes.decrypt(bytes));
                            Log.e("success", "请求成功:" + content);
                        }
                    });
                }
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

源码打包下载地址:

https://github.com/fengfanchen/Java/tree/master/AES%26RSA%26DHDemo

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
先运行safechat包里的greetigserver.class,之后运行greetingclient.class即可。 如遇报错,请参考:https://blog.csdn.net/fengzun_yi/article/details/104497160 实现过程: 1. 采用TCP通信协议完成接收者发送者双方的消息传递。 2. 利用Diffie-Hellman密钥交换协议生成对称加密通信的通信密钥。 3. 为防止间人攻击,采用RSA非对称加密算法协助DH算法完成密钥交换。具体过程如下: a. 接收者与发送者双方各自利用RSA算法生成自己的公私钥,并生成数字证书,并在一个CA进行认证。 b. 在DH密钥交换阶段,A生成A的DH协商密钥用于发送给B,该密钥与接收方私钥生成最终通信密钥。发送DH密钥时,A先用自己的私钥加密DH协商密钥,再去CA获得一个真实的B的公钥,用B的公钥加密过的协商密钥再做一次加密,发送给B。(因为是用B的公钥加密过,只有B有B的私钥,所以接收信息只有B自己可以解密查看,又因为是用A的私钥加密过的,只有A有A的私钥,所以只有用A的公钥可以进行解密,所以可以保证协商密钥确实是A发送过来的,而且发送的信息也无法被间人解密。)B收到信息之后,先用自己的私钥解密,然后去CA获得A的公钥再对消息解密一次,获得A的DH密钥。B发给A的过程同上。 c. 之后双方执行DH生成本地密钥的过程。A利用B发送过来的密钥和A的DH私钥生成通信密钥。B利用A发送过来的密钥和B的DH私钥生成通信密钥。根据DH原理,两者生成的通信密钥是相同的。 4. 利用上一步生成的通信密钥,采用AES对称加密算法进行加密通信。 为了方便起见,并没用对A和B双方进行颁发证书的操作,A的公钥默认B已经从CA获得,B的公钥默认A已经从CA获得。并且采用java控制台交互,仅仅为演示原理及简单效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT1995

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值