android加密的即时通信软件 -服务器端


在这里插入图片描述
这是服务器端,整个通信软件客户端,服务器端源码包已经上传到我的资源。

manifests

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.socketserver">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".Activity.Function_Socket_Server">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>

java

Activity

BaseEventAcitivity

package com.example.socketserver.Activity;


import android.os.Bundle;
import android.view.Window;

import androidx.appcompat.app.AppCompatActivity;

import org.greenrobot.eventbus.EventBus;

import butterknife.ButterKnife;


public abstract class BaseEventActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        getIntentData();
        setContentView(getLayoutResId());
        ButterKnife.bind(this);// 相当于 activity.subtitle = (TextView) activity.findViewById(R.id.subtitle);
        EventBus.getDefault().register(this);//注册订阅者
        init();
    }

    protected void getIntentData() {
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    protected abstract void init();

    protected abstract int getLayoutResId();
}

Function_Socket_Server

package com.example.socketserver.Activity;


import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.example.socketserver.Thread.ListenThread;
import com.example.socketserver.Util.AESUtil;
import com.example.socketserver.Util.ConstantUtil;
import com.example.socketserver.Service.LocalService;
import com.example.socketserver.R;
import com.example.socketserver.Util.ToolUtil;

import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;

import butterknife.BindView;
import butterknife.OnClick;


/**
 * 服务器界面
 */
public class Function_Socket_Server extends BaseEventActivity {
    @BindView(R.id.tv_localAddress)
    TextView tv_localAddress;
    @BindView(R.id.tv_receivedContent)
    TextView tv_receivedContent;
    @BindView(R.id.tv_decryptContent)
    TextView tv_decryptContent;
    @BindView(R.id.edtTxt_server_Content)
    TextView edtTxt_server_Content;
    @BindView(R.id.edtTxt_server_clientAddress)
    TextView edtTxt_server_clientAddress;


    @Override
    protected int getLayoutResId() {
        return R.layout.function_socket_server;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new ListenThread(ConstantUtil.port,Function_Socket_Server.this).start();
    }

    @Override
    protected void init() {
        Log.d("Function_Socket_Server","init");
        tv_localAddress.setText(ToolUtil.getHostIP());//获取本机局域网ip地址

    }


    @OnClick({R.id.btn_startListener, R.id.btn_stopListener, R.id.btn_getUser,R.id.btn_server_encryptAndSend})
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_startListener://启动监听
                break;
            case R.id.btn_stopListener://停止监听
                break;
            case R.id.btn_getUser://刷新连接到此设备的IP并清空之前接收到的数据
                ArrayList<String> connectedIP = getConnectedIP();
                StringBuilder resultList = new StringBuilder();

                for (String ip : connectedIP) {
                    resultList.append(ip);
                    resultList.append("\n");
                }
                Toast.makeText(Function_Socket_Server.this, "连接到手机上的Ip是"+ resultList.toString(), Toast.LENGTH_LONG).show();
                tv_decryptContent.setText("");
                tv_receivedContent.setText("");
                break;
            case R.id.btn_server_encryptAndSend:
                Toast.makeText(Function_Socket_Server.this, "未实现功能", Toast.LENGTH_SHORT).show();
                break;
        }
    }
    //订阅事件处理,处理 ListenThread 的 EventBus.getDefault().post(str);
    @Subscribe(threadMode = ThreadMode.MAIN)//在ui线程执行
    public void getData(String data) {
        //dismissProgressDialog();
        switch (data) {
            default:
                tv_receivedContent.append(data+"\n");
                tv_decryptContent.append(AESUtil.decrypt(ConstantUtil.password, data)+"\n");
                break;

        }

    }

    /**
     * 获取连接到本机热点上的手机ip
     */
    private ArrayList<String> getConnectedIP() {
        ArrayList<String> connectedIP = new ArrayList<>();
        try {
            //通过读取配置文件实现
            BufferedReader br = new BufferedReader(new FileReader(
                    "/proc/net/arp"));
            String line;
            while ((line = br.readLine()) != null) {
                String[] splitted = line.split(" +");
                if (splitted.length >= 4) {
                    String ip = splitted[0];
                    connectedIP.add(ip);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connectedIP;
    }

}

SQL

SQLiteHelper

package com.example.socketserver.SQL;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class SQLiteHelper extends SQLiteOpenHelper {
    //构造socket的数据库
    public SQLiteHelper(Context context) {
        super(context, "socket.db", null, 1);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        //创建一个名字为 information,3列的表格
        //列:1: _id,2: USERNAME,3: PASSWORD
        db.execSQL("CREATE TABLE information(_id INTEGER PRIMARY KEY AUTOINCREMENT," +
                "USERNAME VARCHAR(20),PASSWORD VARCHAR(30),PRIVATEKEY VARCHAR(1250),PUBLICKEY VARCHAR(350))");//,LATESTIP VARCHAR(15)
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}

Thread

ListenThread

package com.example.socketserver.Thread;


import android.content.Context;
import android.util.Log;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 监听线程
 */
public class ListenThread extends Thread {
    private ServerSocket serverSocket;
    private Context context;


    //构造函数,传递,端口,上下文
    public ListenThread(int port, Context context) {
        try {
            serverSocket = new ServerSocket(port);//服务器端:创建绑定到指定 端口 的服务器套接字
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.context = context;
    }

    @Override
    public void run() {
        Log.d("ListenThread","run");
        while (true) {//不断得循环等待连接,读取数据
            try {
                if (serverSocket != null) {
                    Socket socket = serverSocket.accept();//调用accept()方法 等待客户连接
                    final String address = socket.getRemoteSocketAddress().toString();//获取发送客户端的地址
                    Log.d("ListenThread","new clients socket address:"+address);

                    //每一个socket单独开启一个线程
                    ServerHandleSocketThread serverThread = new ServerHandleSocketThread(socket,context);
                    serverThread.start();
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

ServerHandleSocketThread

package com.example.socketserver.Thread;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.util.Log;

import androidx.annotation.RequiresApi;

import com.example.socketserver.SQL.SQLiteHelper;
import com.example.socketserver.Util.AESUtil;
import com.example.socketserver.Util.ClientSocket;
import com.example.socketserver.Util.ConstantUtil;
import com.example.socketserver.Util.RSAUtil;
import com.example.socketserver.Util.SRConstantsUtil;

import org.greenrobot.eventbus.EventBus;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.Set;

class ServerHandleSocketThread extends Thread{
    private Socket socket;
    private Context context;

    private boolean exit = false;
    //在构造中得到要单独会话的socket
    public ServerHandleSocketThread(Socket socket, Context context) {
        this.socket = socket;
        this.context = context;
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void run() {
        super.run();
        if(!exit)
        while(true){
            if(exit == true)break;
            try {
                InputStream inputStream = socket.getInputStream();//实现客户端和服务器端在线程上对话, 读取输入流
                if (inputStream != null) {
                    //读取接收到的数据
                    BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
                    String dataPacket = in.readLine();//读一行数据

                    //发送过来的数据不为空,判断数据内容
                    if (dataPacket != null) {
                        String clientData = AESUtil.decrypt(ConstantUtil.password, dataPacket);
                        int cmdBeginIndex1=clientData.indexOf(":")+1;
                        int cmdEndIndex1 = clientData.indexOf("}");
                        String cmd=clientData.substring(cmdBeginIndex1,cmdEndIndex1);

                        //登录,
                        if (cmd.equals("login")) {
                            Log.d("HandleSocketThread", "handle login");
                            //获取登录的用户名
                            int userNameBeginIndex = clientData.indexOf(":",cmdBeginIndex1) + 1;
                            int userNameEndIndex = clientData.indexOf("}",userNameBeginIndex);
                            String username = clientData.substring(userNameBeginIndex, userNameEndIndex);

                            //获取登录的密码
                            int passwordBeginIndex = clientData.indexOf(":", userNameBeginIndex) + 1;
                            int passwordEndIndex = clientData.indexOf("}", userNameEndIndex + 1);
                            String password = clientData.substring(passwordBeginIndex, passwordEndIndex);

                            SQLiteDatabase db;
                            ContentValues values;
                            SQLiteHelper helper = new SQLiteHelper(context);
                            db = helper.getReadableDatabase();
                            //执行查询的SQL语句,查询账号,密码是否存在数据库中
                            //密码加密加密存储,所以得把得到的密码加密查询
                            Cursor cursor = db.rawQuery("select * from information where USERNAME=? and PASSWORD=?",
                                    new String[]{username, AESUtil.encrypt(ConstantUtil.password, password)});

                            //查无此数据,返回
                            if (cursor.getCount() == 0) {
                                Log.d("HandleSocketThread", "login,无此用户数据");
                                //返回登录失败信息
                                writeResponse(socket, SRConstantsUtil.LOGIN_FAILED);
                                socket.close();
                                exit = true;
                            }
                            //有此数据,准许登录
                            else if(cursor.getCount()!=0){
                                cursor.moveToFirst();
                                Log.d("HandleSocketThread ", "Login success "+"账号:" + cursor.getString(1) + "密码:" + cursor.getString(2));

                                Set<String> keyset = ClientSocket.keySet();
                                Iterator<String> it = keyset.iterator();
                                while (it.hasNext()) {
                                    String username1 = it.next();
                                    if (username1.equals(username)) {
                                        //返回该账号已经登录信息
                                        writeResponse(socket,SRConstantsUtil.LOGIN_ALREADY);
                                        cursor.close();
                                        db.close();
                                        return;
                                    }
                                }
                                ClientSocket.put(username,socket);
                                Log.d("HandleSocketThread","add socket,clientSocketSize:"+String.valueOf(ClientSocket.size()));
                                //返回登录成功信息
                                writeResponse(socket,SRConstantsUtil.LOGIN_SUCCESS);
                            }
                            cursor.close();
                            db.close();
                        }
                        //连接通信,保持socket存在获取客户聊天使用的socket
                        else if(cmd.equals("connect")){
                            Log.d("HandleSocketThread", "connect ");
                            //获取登录的用户名
                            int userNameBeginIndex = clientData.indexOf(":",cmdBeginIndex1) + 1;
                            int userNameEndIndex = clientData.indexOf("}",userNameBeginIndex);
                            String username = clientData.substring(userNameBeginIndex, userNameEndIndex);

                            //返回连接成功信息
                            writeResponse(socket,SRConstantsUtil.CONNECTSUCCESS);
                        }
                        //获得好友公钥
                        else if(cmd.equals("addFriend")){
                            //获取添加的好友的用户名
                            int userNameBeginIndex = clientData.indexOf(":",cmdBeginIndex1) + 1;
                            int userNameEndIndex = clientData.indexOf("}",userNameBeginIndex);
                            String frinedUsername = clientData.substring(userNameBeginIndex, userNameEndIndex);

                            //查询数据库有无此数用户名
                            SQLiteDatabase db;
                            ContentValues values;
                            SQLiteHelper helper = new SQLiteHelper(context);
                            db = helper.getReadableDatabase();
                            //执行查询的SQL语句
                            Cursor cursor = db.rawQuery("select * from information where USERNAME=? ",
                                    new String[]{frinedUsername});
                            //查无此数据,存储返回
                            if (cursor.getCount() == 0) {
                                Log.d("HandleSocketThread", "no this frinedUsername ");
                                //返回获取公钥错误
                                writeResponse(socket,SRConstantsUtil.NOFRIENDACCOUNT);
                            }
                            else {
                                cursor.moveToFirst();//这句话一定要有,不然无法选中第一条!!!!!
                                String publicKey = cursor.getString(4);
                                if(publicKey != null){
                                    Log.d("ServerThread", "发送公钥");
                                    String publicKeyPacket = "{response:sendPublicKey}{key:"+publicKey+"}";
                                    writeResponse(socket,publicKeyPacket);
                                }
                            }
                            cursor.close();
                            db.close();
                        }
                        //自己私钥
                        else if(cmd.equals("getPrivateKey")){
                            //{cmd:getPrivateKey}{username:"+username+"}"
                            //获取登录的用户名
                            int userNameBeginIndex = clientData.indexOf(":",cmdBeginIndex1) + 1;
                            int userNameEndIndex = clientData.indexOf("}",userNameBeginIndex);
                            String username = clientData.substring(userNameBeginIndex, userNameEndIndex);

                            //查询数据库有无此数用户名
                            SQLiteDatabase db;
                            ContentValues values;
                            SQLiteHelper helper = new SQLiteHelper(context);
                            db = helper.getReadableDatabase();
                            //执行查询的SQL语句
                            Cursor cursor = db.rawQuery("select * from information where USERNAME=? ",
                                    new String[]{username});
                            //查无此数据,存储返回
                            if (cursor.getCount() == 0) {
                                Log.d("HandleSocketThread", "get public key error");
                                //返回获取公钥错误
                                writeResponse(socket,SRConstantsUtil.GETPUBLICKEYERROR);
                            }
                            else {
                                cursor.moveToFirst();//这句话一定要有,不然无法选中第一条!!!!!
                                String privateKey = cursor.getString(3);
                                Log.d("ServerThread", "发送私钥");
                                //返回注册失败信息
                                String publicKeyPacket = "{response:sendPrivateKey}{key:"+privateKey+"}";
                                writeResponse(socket,publicKeyPacket);
                            }
                            cursor.close();
                            db.close();
                        }
                        //发送消息,
                        else if (cmd.equals("sendMsg")) {
                            Log.d("HandleSocketThread", "handle sendmsg");
                            boolean recIsOnline = false;

                            //提取接收者账号
                            //{cmd:sendMsg}{receiverAccount:123}{msg:xxxx}{sender:xxx}
                            int recBeginIndex=clientData.indexOf(":",cmdBeginIndex1)+1;
                            int recIndex=clientData.indexOf("}", recBeginIndex);
                            String recAccount=clientData.substring(recBeginIndex,recIndex);

                            //根据接收者账号 遍历寻找是否在线
                            //判断登录存储的map中有 数据接收者账号
                            //有就从map中找到 相应接收者账号的socket,提取cilentData中的msg,并且发送消息出去给相应客户
                            //返回 发送者发送成功的消息,关闭发送者 发送数据的socket
                            Set<String> keyset = ClientSocket.keySet();
                            Iterator<String> it = keyset.iterator();
                            while (it.hasNext()){
                                String username = it.next();
                                if(username.equals(recAccount))
                                {
                                    Log.d("HandleSocketThread","handle sendmsg,search and get recAccount:"+username);
                                    Log.d("HandleSocketThread","handle sendmsg,receiver is online ");
                                    recIsOnline = true;
                                    int msgBeginIndex=clientData.indexOf(":",recBeginIndex)+1;
                                    int msgIndex=clientData.indexOf("}", recIndex+1);
                                    String msg=clientData.substring(msgBeginIndex,msgIndex);

                                    int nextBeginIndex=clientData.indexOf("{",msgBeginIndex);
                                    int sendBeginIndex=clientData.indexOf(":",nextBeginIndex)+1;
                                    int sendIndex=clientData.indexOf("}", sendBeginIndex);
                                    String sendAccount=clientData.substring(sendBeginIndex,sendIndex);

                                    Log.d("HandleSocketThread","handle sendmsg,sendAccount is "+sendAccount+",now send "+msg+" to "+username);

                                    String msgPacket = "{response:transmit}{sender:"+sendAccount+"}{msg:"+msg+"}";
                                    //根据keyset 找到 对应接收者的socket
                                    Socket socket1 = ClientSocket.get(username);
                                    writeResponse(socket1,msgPacket);
                                    Log.d("HandleSocketThread","handle sendmsg,msg has sent");

                                    //返回发送成功信息
                                    writeResponse(socket,SRConstantsUtil.MSGSEND_SUCCESS);
                                    //找到发送对象并且发送完毕,退出本次发送循环
                                    break;
                                }
                            }
                            //不在线,在线标志位 由遍历过程 改变
                            if(recIsOnline == false){
                                Log.d("HandleSocketThread","handle sendmsg,receiver isn't online ");
                                //返回接收者不在线信息
                                writeResponse(socket,SRConstantsUtil.MSGSEND_FAILED_NOT_ONLINE);
                            }
                            exit = true;
                        }
                        //注册,关闭socket
                        else if (cmd.equals("register")) {
                            Log.d("HandleSocketThread", "handle register");
                            //获取注册的用户名
                            int userNameBeginIndex = clientData.indexOf(":",cmdBeginIndex1) + 1;
                            int userNameEndIndex = clientData.indexOf("}",userNameBeginIndex);
                            String username = clientData.substring(userNameBeginIndex, userNameEndIndex);
                            //获取注册的密码
                            int passwordBeginIndex = clientData.indexOf(":", userNameBeginIndex) + 1;
                            int passwordEndIndex = clientData.indexOf("}", userNameEndIndex + 1);
                            String password = clientData.substring(passwordBeginIndex, passwordEndIndex);

                            //查询数据库有无此数用户名
                            SQLiteDatabase db;
                            ContentValues values;
                            SQLiteHelper helper = new SQLiteHelper(context);
                            db = helper.getReadableDatabase();
                            //执行查询的SQL语句
                            Cursor cursor = db.rawQuery("select * from information where USERNAME=? ",
                                    new String[]{username});

                            //查无此数据,存储返回
                            if (cursor.getCount() == 0) {
                                Log.d("HandleSocketThread", "register,注册用户名无冲突");
                                db = helper.getWritableDatabase();
                                values = new ContentValues();//创建Contentvalues对象
                                values.put("USERNAME", username);//将数据添加到ContentValues对象
                                values.put("PASSWORD", AESUtil.encrypt(ConstantUtil.password, password));

                                RSAUtil.genKeyPair();
                                String publicKey = RSAUtil.getPublicKey();
                                String privateKey = RSAUtil.getPrivateKey();
                                values.put("PRIVATEKEY", privateKey);
                                values.put("PUBLICKEY", publicKey);
                                db.insert("information", null, values);
                                Log.d("HandleSocketThread", "register,存储成功");
                                //返回注册成功信息
                                writeResponse(socket,SRConstantsUtil.REGISTER_SUCCESS);
                            }
                            else {
                                Log.d("ServerThread", "注册用户名冲突");
                                //返回注册失败信息
                                writeResponse(socket,SRConstantsUtil.REGISTER_FAILED);
                            }
                            cursor.close();
                            db.close();
                            socket.close();
                            exit = true;
                        }
                        //用户退出APP消息,关闭socket,删除相应的map中的socket
                        else if(cmd.equals("exitApp")) {
                            Log.d("HandleSocketThread", "handle exist");
                            //{cmd:exitAPP}{username:123}
                            int userNameBeginIndex=clientData.indexOf(":",cmdBeginIndex1)+1;
                            int userNameEndIndex = clientData.indexOf("}",userNameBeginIndex);
                            String username=clientData.substring(userNameBeginIndex,userNameEndIndex);
                            ClientSocket.remove(username);
                            Log.d("HandleSocketThread","handle exist,clientSocketSize:"+String.valueOf(ClientSocket.size()));
                            //返回收到退出信息
                            writeResponse(socket,SRConstantsUtil.EXISTAPPNORMAL);
                            socket.close();
                            exit = true;
                        }
                        else Log.d("HandleSocketThread","数据格式错误");
                        EventBus.getDefault().post(dataPacket);//发布事件,把获取到的信息显示出来
                    }
                }
            }
            catch (IOException | NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
    }


    private void writeResponse(Socket socket,String response) throws IOException {
        OutputStream outputStream = socket.getOutputStream();
        OutputStreamWriter opsw = new OutputStreamWriter(outputStream);//
        BufferedWriter writer = new BufferedWriter(opsw);
        writer.write(AESUtil.encrypt(ConstantUtil.password, response)+ "\r\n\r\n");//由于socket使用缓冲区进行读写数据,因此使用\r\n\r\n用于表明数据已写完.不加这个会导致数据无法发送
        writer.flush();
    }
}

Util

AESUtil

package com.example.socketserver.Util;

import android.util.Log;

import java.io.UnsupportedEncodingException;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES加密工具类
 */
public class AESUtil {

    //    private static final String CipherMode = "AES/ECB/PKCS5Padding";使用ECB加密,不需要设置IV,但是不安全
    private static final String CipherMode = "AES/CFB/NoPadding";//使用CFB加密,需要设置IV;CFB(Cipher FeedBack Mode,加密反馈),不填充

    /**
     * 生成加密后的密钥
     *
     * @param password 密钥种子
     * @return isSucceed
     */
    private static SecretKeySpec createKey(String password) {
        byte[] data = null;
        if (password == null) {
            password = "";
        }
        StringBuilder sb = new StringBuilder(32);//32位容量的字符串
        sb.append(password);//字符串追加密码
        while (sb.length() < 32) {
            sb.append("0");//少于32位,追加‘0’
        }
        if (sb.length() > 32) {
            //setLength(newLength)
            //如果 newLength 参数小于当前长度,则长度将更改为指定的长度。
            //如果 newLength 参数大于或等于当前长度,则将追加有效的 null 字符 ('u0000'),使长度满足 newLength 参数。
            sb.setLength(32);
        }

        try {
            data = sb.toString().getBytes("UTF-8");//得到 使用UTF-8编码表 的一个系统默认的编码格式的 字节数组
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return new SecretKeySpec(data, "AES");//根据32字节的数据,生成一个AES算法生成的密钥
    }

    // /** 加密字节数据 **/
    private static byte[] encrypt(byte[] content, String password) {
        try {
            SecretKeySpec key = createKey(password);//根据密钥种子生成密钥
            System.out.println(key);
            Cipher cipher = Cipher.getInstance(CipherMode);

            //初始化Cipher,mode指定是加密还是解密,key为公钥或密钥;ENCRYPT_MODE加密模式,
            // 实例化IvParameterSpec对象,使用指定的初始化向量
            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(
                    new byte[cipher.getBlockSize()]));


            //使用CFB加密CFB(Cipher FeedBack Mode,加密反馈)、不填充的方式
            //init为 加密形式
            //返回btye[]数组
            return cipher.doFinal(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // /** 加密(结果为16进制字符串) **/
    public static String encrypt(String password, String content) {
        Log.d("加密前", "seed=" + password + "\ncontent=" + content);
        byte[] data = null;//byte字节数组
        try {
            data = content.getBytes("UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        data = encrypt(data, password);//加密字节数据
        String result = byte2hex(data);//字节转hex
        Log.d("加密后", "result=" + result);
        return result;
    }

    // /** 解密字节数组 **/
    private static byte[] decrypt(byte[] content, String password) {

        try {
            SecretKeySpec key = createKey(password);
            Cipher cipher = Cipher.getInstance(CipherMode);
            cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(
                    new byte[cipher.getBlockSize()]));

            return cipher.doFinal(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // /** 解密16进制的字符串为字符串 **/
    public static String decrypt(String password, String content) {
        Log.d("解密前", "seed=" + password + "\ncontent=" + content);
        byte[] data = null;
        try {
            data = hex2byte(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        data = decrypt(data, password);
        if (data == null)
            return null;
        String result = null;
        try {
            result = new String(data, "UTF-8");
            Log.d("解密后", "result=" + result);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    // /** 字节数组转成16进制字符串 **/
    private static String byte2hex(byte[] b) { // 一个字节的数,
        StringBuilder sb = new StringBuilder(b.length * 2);
        String tmp ;
        for (byte aB : b) {
            // 整数转成十六进制表示
            tmp = (Integer.toHexString(aB & 0XFF));
            if (tmp.length() == 1) {
                sb.append("0");
            }
            sb.append(tmp);
        }
        return sb.toString().toUpperCase(); // 转成大写
    }

    // /** 将hex字符串转换成字节数组 **/
    private static byte[] hex2byte(String inputString) {
        if (inputString == null || inputString.length() < 2) {
            return new byte[0];
        }
        inputString = inputString.toLowerCase();
        int l = inputString.length() / 2;
        byte[] result = new byte[l];
        for (int i = 0; i < l; ++i) {
            String tmp = inputString.substring(2 * i, 2 * i + 2);
            result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
        }
        return result;
    }
}

ClientSocket

package com.example.socketserver.Util;

import java.net.Socket;
import java.util.HashMap;
import java.util.Set;

public class ClientSocket {
    private static HashMap<String, Socket> clients = new HashMap<String,Socket>();// 创建一个集合存放所有的客户端 的用户名,和客户socket

    public static void put(String username, Socket userSocket){
        clients.put(username,userSocket);
    }

    public static int size() {
        return clients.size();
    }

    public static Socket get(String username) {
        return clients.get(username);
    }

    public static void remove(String username) {
        clients.remove(username);
    }

    public static Set<String> keySet() {
        return clients.keySet();
    }
}

ConstantUtil

package com.example.socketserver.Util;

/**
 * 常量类
 */
public class ConstantUtil {
    public static final int TIME_MILLIS = 5 * 1000;//连接超时时间
    public static final int port = 25256;//端口号
    public static final String password = "123456885";//加密所使用的密钥
    public static final String CODE_TIMEOUT = "pzl0";//连接超时
    public static final String CODE_SUCCESS = "pzl1";//连接成功
    public static final String CODE_UNKNOWN_HOST = "pzl2";//错误-未知的host

    public static final String SERVERIP = "SERVERIP";//服务器地址

}

RSAUtil

package com.example.socketserver.Util;

import android.os.Build;

import androidx.annotation.RequiresApi;

import java.util.Base64;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
public class RSAUtil {
    /**
     * 密钥长度 于原文长度对应 以及越长速度越慢
     */
    private final static int KEY_SIZE = 1536;

    private static final String CipherMode = "RSA";
    /**
     * 用于封装随机产生的公钥与私钥
     */
    private static Map<String, String> keyMap = new HashMap<String, String>();
    //公钥
    public static final String PUBLIC_KEY = "RSAPublicKey";
    //私钥
    public static final String PRIVATE_KEY = "RSAPrivateKey";

    /**
     * 随机生成密钥对
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    public static void genKeyPair() throws NoSuchAlgorithmException {
        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(CipherMode);
        // 初始化密钥对生成器
        keyPairGen.initialize(KEY_SIZE, new SecureRandom());
        // 生成一个密钥对,保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 得到私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 得到公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
        // 得到私钥字符串
        String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());
        // 将公钥和私钥保存到Map
        //0表示公钥
        keyMap.put(PUBLIC_KEY, publicKeyString);
        //1表示私钥
        keyMap.put(PRIVATE_KEY, privateKeyString);
    }
    public static String getPublicKey(){
        return keyMap.get(PUBLIC_KEY);
    }
    public static String getPrivateKey(){
        return keyMap.get(PRIVATE_KEY);
    }

    /**
     * RSA公钥加密
     *
     * @param str       加密字符串
     * @param publicKey 公钥
     * @return 密文
     * @throws Exception 加密过程中的异常信息
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    public static String encrypt(String str, String publicKey) throws Exception {
        //base64编码的公钥
        byte[] decoded = Base64.getDecoder().decode(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(CipherMode).generatePublic(new X509EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance(CipherMode);
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        String outStr = Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes("UTF-8")));
        return outStr;
    }

    /**
     * RSA私钥解密
     *
     * @param str        加密字符串
     * @param privateKey 私钥
     * @return 明文
     * @throws Exception 解密过程中的异常信息
     */
    public static String decrypt(String str, String privateKey) throws Exception {
        //64位解码加密后的字符串
        byte[] inputByte = Base64.getDecoder().decode(str);
        //base64编码的私钥
        byte[] decoded = Base64.getDecoder().decode(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(CipherMode).generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance(CipherMode);
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }
}

SRConstantsUtil

package com.example.socketserver.Util;

public class SRConstantsUtil {
    public static final String REGISTER_SUCCESS = "{response:register_success}";//注册成功
    public static final String REGISTER_FAILED = "{response:register_failed}";//注册失败


    public static final String LOGIN_SUCCESS = "{response:login_success}";//登录成功
    public static final String LOGIN_FAILED = "{response:login_failed}";//登录识别
    public static final String LOGIN_ALREADY = "{response:login_already}";//登录识别

    public static final String MSGSEND_SUCCESS = "{response:send_msg_success}";//连接成功
    public static final String MSGSEND_FAILED = "{response:send_msg_failed}";//连接成功
    public static final String MSGSEND_FAILED_NOT_ONLINE = "{response:receiver_not_online}";//接收者不在线
    public static final String MSGSEND_FAILED_NOT_EXIST = "{response:receiver_not_exist}";//接收者错误

    public static final String EXISTAPPNORMAL = "{response:exist_normal}";//退出成功
    public static final String EXISTAPPABNORMAL = "{response:exist_abnormal}";//退出错误

    public static final String CONNECTSUCCESS = "{response:connect_success}";//连接成功
    public static final String NOFRIENDACCOUNT = "{response:no_user_account}";//没有此好友用户

    public static final String GETPUBLICKEYERROR = "{response:get_privateKey_error}";//获取公钥错误
    //public static final String PRIVATEKEY = "{response:privateKey}{key:";//获取公钥错误
}

ToolUtil

package com.example.socketserver.Util;

import android.util.Log;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;


/**
 * 工具类
 */
public class ToolUtil {
    /**
     * 获取ip地址
     * 如果是移动网络,会显示自己的公网IP,如果是局域网,会显示局域网IP
     * 因此本例中服务器端需要断开移动网络以得到本机局域网IP
     */
    public static String getHostIP() {

        String hostIp = null;
        try {
            Enumeration nis = NetworkInterface.getNetworkInterfaces();
            InetAddress ia;
            while (nis.hasMoreElements()) {
                NetworkInterface ni = (NetworkInterface) nis.nextElement();
                Enumeration<InetAddress> ias = ni.getInetAddresses();
                while (ias.hasMoreElements()) {
                    ia = ias.nextElement();
                    if (ia instanceof Inet6Address) {
                        continue;// skip ipv6
                    }
                    String ip = ia.getHostAddress();
                    if (!"127.0.0.1".equals(ip)) {
                        hostIp = ia.getHostAddress();
                        break;
                    }
                }
            }
        } catch (SocketException e) {
            Log.i("error", "SocketException");
            e.printStackTrace();
        }
        return hostIp;

    }

    /**
     * 判断地址是否为IPV4地址
     */
    public static boolean IsIpv4(String ipv4) {
        if (ipv4 == null || ipv4.length() == 0) {
            return false;//字符串为空或者空串
        }
        String[] parts = ipv4.split("\\.");//因为java doc里已经说明, split的参数是reg, 即正则表达式, 如果用"|"分割, 则需使用"\\|"
        if (parts.length != 4) {
            return false;//分割开的数组根本就不是4个数字
        }
        for (String part : parts) {
            try {
                int n = Integer.parseInt(part);
                if (n < 0 || n > 255) {
                    return false;//数字不在正确范围内
                }
            } catch (NumberFormatException e) {
                return false;//转换数字不正确
            }
        }
        return true;
    }
}


res

layout

funtion_socket_server.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@mipmap/bg2"
    >


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="55dp">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:textSize="30dp"
            android:textColor="#fec"
            android:text="网络加密-服务器端" />


    </RelativeLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="10dp"
        android:layout_margin="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="本机地址:"
            android:textSize="18sp"
            android:textColor="#fec"/>

        <TextView
            android:id="@+id/tv_localAddress"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:textColor="#fec"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_margin="5dp">

        <Button
            android:id="@+id/btn_startListener"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="启动监听"
            android:background="#5fff"
            android:textSize="18sp"
            android:textColor="#fec"/>


        <Button
            android:id="@+id/btn_stopListener"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="停止监听"
            android:textSize="18sp"
            android:textColor="#fec"
            android:background="#5791"/>

        <Button
            android:id="@+id/btn_getUser"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="刷新用户"
            android:textColor="#fec"
            android:textSize="18sp"
            android:background="#5fff"
            android:padding="5dp"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="10dp"
        android:layout_margin="5dp"
        android:visibility="gone">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="好友账号:"
            android:textSize="18sp"
            android:textColor="#fec"/>

        <EditText
            android:id="@+id/edtTxt_server_clientAddress"
            android:layout_width="match_parent"
            android:text="192.168.1.105"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:textColor="#fec"/>
    </LinearLayout>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_margin="5dp"
        android:visibility="gone">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="发送文本内容:"
                android:textColor="#fec"
                android:textSize="15sp"/>

            <EditText
                android:id="@+id/edtTxt_server_Content"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#fff"
                android:padding="10dp"
                android:text="123木头人"
                android:textColor="#fec"
                android:backgroundTint="#33000000" />
        </LinearLayout>
    </ScrollView>
    <Button
        android:id="@+id/btn_server_encryptAndSend"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:text="加密并发送"
        android:textColor="#fec"
        android:background="#5791"
        android:layout_margin="5dp"
        android:visibility="gone"/>


    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="5dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">


            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="接收到的密文:"
                android:textColor="#fec"
                android:textSize="18sp"/>

            <TextView
                android:id="@+id/tv_receivedContent"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:padding="10dp"
                android:textColor="#fec"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="解密后的明文:"
                android:textColor="#fec"
                android:textSize="18sp"/>

            <TextView
                android:id="@+id/tv_decryptContent"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:padding="10dp"
                android:textColor="#fec"/>

        </LinearLayout>

    </ScrollView>

</LinearLayout>

values

styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>

gradle与客户端一样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值