网络安全实验——安全通信软件safechat的设计

这篇具有很好参考价值的文章主要介绍了网络安全实验——安全通信软件safechat的设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

网络安全实验——安全通信软件safechat的设计

仅供参考,请勿直接抄袭,抄袭者后果自负。

仓库地址:

后端地址:https://github.com/yijunquan-afk/safechat-server

前端地址: https://github.com/yijunquan-afk/safechat-client

CosUpload.java中的COS设置,需要自己配

1 设计要求

结合所学安全机制设计实现一个简单的安全通信软件,包含机密性,消息认证等基本功能。并考虑其中涉及的密钥分配方式与机密性算法等相关问题的解决.实现方法不限,使用机制不限。

要求:

1、 独立完成

2、 具有完整的流程设计,报文格式等相关分析。

3、 具备自圆其说的安全性设计思考

2 设计分工

3 设计原理

SHA-2

SHA-2,名称来自于安全散列算法2(英语:Secure Hash Algorithm 2)的缩写,一种密码散列函数算法标准,由美国国家安全局研发[3],由美国国家标准与技术研究院(NIST)在2001年发布。属于SHA算法之一,是SHA-1的后继者。其下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。

RSA

RSA加密算法是一种非对称加密算法,在公开密钥加密和电子商业中被广泛使用。RSA是由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)在1977年一起提出的。当时他们三人都在麻省理工学院工作。RSA 就是他们三人姓氏开头字母拼在一起组成的。

极大整数做因数分解的难度决定了 RSA 算法的可靠性。换言之,对一极大整数做因数分解愈困难,RSA 算法愈可靠。假如有人找到一种快速因数分解的算法的话,那么用 RSA 加密的信息的可靠性就会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的 RSA 钥匙才可能被强力方式破解。到2020年为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被破解的。

WebSocket协议

WebSocket是双向的,在客户端-服务器通信的场景中使用的全双工协议,与HTTP不同,它以ws://或wss://开头。它是一个有状态协议,这意味着客户端和服务器之间的连接将保持活动状态,直到被任何一方(客户端或服务器)终止。在通过客户端和服务器中的任何一方关闭连接之后,连接将从两端终止。

以客户端-服务器通信为例,每当启动客户端和服务器之间的连接时,客户端-服务器进行握手随后创建一个新的连接,该连接将保持活动状态,直到被他们中的任何一方终止。建立连接并保持活动状态后,客户端和服务器将使用相同的连接通道进行通信,直到连接终止。

新建的连接被称为WebSocket。一旦通信链接建立和连接打开后,消息交换将以双向模式进行,客户端-服务器之间的连接会持续存在。如果其中任何一方(客户端服务器)宕掉或主动关闭连接,则双方均将关闭连接。套接字的工作方式与HTTP的工作方式略有不同,状态代码101表示WebSocket中的交换协议。

safechat,# 计算机网络安全与管理,安全,web安全,java

JWT

JWT就是通过JSON形式作为Web应用中的令牌,用于在各方之间安全地将信息作为JSON对象传输。在数据传输过程中还可以完成数据加密,签名等相关处理。

基于JWT认证

首先,前端通过Wb表单将自己的用戶名和密码发送到后端的接口。这一过程一般是一个HTTP POST请求。

2、后端核对用戶名和密码成功后,将用戶的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT(Token)。形成的JWT就是一个形同11.Zzz.xx的字符串。token head.payload.signature

3、后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStorage或sessionStorage.上,退出登录时前端删除保存的JWT即可。

4、前端在每次请求时将JWT放入HTTP Header中的Authorization位。(解决XSS和XSRF问题)

5、后端检查JWT是否存在,如存在验证JWT的有效性。检查签名是否正确,检查Token是否过期,检查Token的接收方是否是自己(可选)

JWT结构

jwt生成的字符串包含有三部分

1、 jwt头信息部分header:标头通常由两部分组成:令牌的类型(即JWT所使用的签名算法,例如HMAC、SHA256或RSA。它会使用Base64编码组成JWT结构的第一部分。

2、 在效载荷Payload:令牌的第二部分是有效负载,其中包含声明。声明是有关实体(通常是用戶)和其他数据的声明。同样的,它会使用Ba$64编码组成JWT结构的第二部分

3、 签名哈希Signature:header和payload都是结果Base64编码过的,中间用.隔开,第三部分就是前面两部分合起来做签名,密钥绝对自己保管好,签名值同样做Base64编码拼接在JWT后面。(签名并编码)

AES

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),又称Rijndael加密法(荷兰语发音: [ˈrɛindaːl],音似英文的“Rhine doll”),是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。现在,高级加密标准已然成为对称密钥加密中最流行的算法之一。

严格地说,AES和Rijndael加密法并不完全一样(虽然在实际应用中两者可以互换),因为Rijndael加密法可以支持更大范围的区块和密钥长度:AES的区块长度固定为128比特,密钥长度则可以是128,192或256比特;而Rijndael使用的密钥和区块长度均可以是128,192或256比特。加密过程中使用的密钥是由Rijndael密钥生成方案产生。

大多数AES计算是在一个特别的有限域完成的。

AES加密过程是在一个4×4的字节矩阵上运作,这个矩阵又称为“体(state)”,其初值就是一个明文区块(矩阵中一个元素大小就是明文区块中的一个Byte)。(Rijndael加密法因支持更大的区块,其矩阵的“列数(Row number)”可视情况增加)加密时,各轮AES加密循环(除最后一轮外)均包含4个步骤:

① AddRoundKey—矩阵中的每一个字节都与该次回合密钥(round key)做XOR运算;每个子密钥由密钥生成方案产生。

② SubBytes—透过一个非线性的替换函数,用查找表的方式把每个字节替换成对应的字节。

③ ShiftRows—将矩阵中的每个横列进行循环式移位。

④ MixColumns—为了充分混合矩阵中各个直行的操作。这个步骤使用线性转换来混合每内联的四个字节。最后一个加密循环中省略MixColumns步骤,而以另一个AddRoundKey取代。

4 整体设计方案

网络协议

本次设计中,我使用了HTTP协议处理一般的网络请求:如登录、注册、好友列表获取、个人信息获取、头像更新等功能。

而好友之间点对点的通信,为了持续快速地沟通,我是用WebSocket协议来处理信息发送请求。

客户端技术选型

客户端负责的是与用户进行交互,因此在实用之外还需要考虑到界面美观整洁,以给用户带来良好的使用体验。因此,前端选择使用 vue + AntDesign 组件库进行界面构建。另一方面,由于需要建立 WebSocket 连接,发送 WebSocket 请求,因此需要引入 WebSocket 相关功能的实现。这里使用的是 socket.io 这一 NodeJS 第三方模块。

safechat,# 计算机网络安全与管理,安全,web安全,java

服务端技术选型

对于服务端,采用了 Java + SpringBoot 为大框架来进行服务端的开发。数据库采用的是经典的关系型数据库 MySql。同时为了建立 WebSocket 连接,处理 WebSocket 请求,选择了 socket.io 的一个 Java 移植版本 netty-socketio。netty-socketio是一个开源的Socket.io服务器端的一个java的实现,它基于Netty框架,可用于服务端推送消息给客户端。

safechat,# 计算机网络安全与管理,安全,web安全,java

整体功能说明

本系统主要包含六个大的功能模块:登陆注册、用户信息获取、信息发送、好友列表显示、头像上传以及退出系统。其中信息发送是本次课程设计最重要的部分,是安全通信的主要体现。

safechat,# 计算机网络安全与管理,安全,web安全,java

5 安全加密部分代码说明

整体设计

safechat,# 计算机网络安全与管理,安全,web安全,java

HTTP加密

Token产生
private static String sign(String userId,String password){
    Algorithm algorithm = Algorithm.HMAC256(password);
    String token = JWT.create()
            .withClaim(CLAIM_USERID_NAME,userId)
            .withExpiresAt(new Date(System.currentTimeMillis()+EXPIRED_TIME/2))
            .sign(algorithm);
    return token;
}

/**
* 生成一个登录token
* @param userId
* @param password
* @return
*/
public static String loginSign(String userId,String password){
    String token = sign(userId,password);
    cache.putToken(token,token);
    return token;
}

每次登录产生Token,并存储在前端的localStorage中,每次发送HTTP的POST和GET请求时加在HTTP Header中的Authorization位。(解决XSS和XSRF问题)

Token认证

后端接收HTTP请求时需要认证Token。

如此做可以认证发送HTTP请求的用户身份,适用于所有HTTP请求

 /**
     * 验证客户端传来token是否有效
     * 验证逻辑顺序如下:
     * 1. token是否为空
     * 2. token中账号是否存在
     * 3. 根据token中账号从数据库中获取真实密码等用户信息,并验证用户信息是否有效
     */
    public static void verifyToken(String clientToken, stu.software.chatroom.common.CommonService commonService){
        if(!StringUtils.hasText(clientToken)){
            //token为空
            throw new RuntimeException("无登录令牌!");
        }

        //从客户端登录令牌中获取当前用户账号
        String userId = JWT.decode(clientToken).getClaim(CLAIM_USERID_NAME).asString();
        if(!StringUtils.hasText(userId)){
            //token中账号不存在
            throw new RuntimeException("登录令牌失效!");
        }

        //取出缓存中的登录令牌
        String cacheToken = cache.getToken(clientToken);
        if(!StringUtils.hasText(cacheToken)){
            //缓存中没有登录令牌
            throw new RuntimeException("登录令牌失效!");
        }

        User user = commonService.getUserById(userId);
        if(user==null){
            //用户不存在
            throw new RuntimeException("用户不存在!");
        }

        //验证Token有效性
        try{
            Algorithm algorithm = Algorithm.HMAC256(user.getU_pwd());
            JWTVerifier jwtVerifier = JWT.require(algorithm).withClaim(CLAIM_USERID_NAME,userId).build();//构建验证器
            jwtVerifier.verify(cacheToken);
        }catch(TokenExpiredException e){
            //令牌过期,刷新令牌
            String newToken = sign(userId,user.getU_pwd());
            cache.putToken(clientToken,newToken);
        }catch(Exception e){
            e.printStackTrace();
            //令牌验证未通过
            throw new RuntimeException("令牌错误!请登录。");
        }

注册密码加密

使用SHA256加密注册时用户使用的密码,数据库中存的是密文,这样可防止数据库被攻击导致密码泄露。

/***
* 利用Apache的工具类实现SHA-256加密
* @return str 加密后的报文
*/
public static String getSHA256Str(String str) {
    MessageDigest messageDigest;
    String encodeSir = str;
    try {
        messageDigest = MessageDigest.getInstance("SHA-256");
        byte[] hash = messageDigest.digest(str.getBytes(StandardCharsets.UTF_8));
        encodeSir = Hex.encodeHexString(hash);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return encodeSir;
}

/**
* 通过该方法将密码加密(实际上并没有)
*/
public static String encodePwd(String u_pwd) {
    // 密码通过此方法解密并再加密
    return getSHA256Str(u_pwd);
}

登录密码加密

登录时,前端输入明文密码,使用SHA256加密该密码以后,再加数据发送到后端。后端根据该加密后的密码与数据库比对,从而验证用户身份。

此做法避免了前端请求数据被拦截导致密码泄露。

import { sha256 } from 'js-sha256';

/**
 * 加密方法
 */
export function PASSWORD(str) {
    let encodedStr = str;
    encodedStr = sha256(encodedStr);
    return encodedStr;
}
const login = () => {
  post("/user/login", {
    u_name: u_name.value,
    u_pwd: PASSWORD(u_pwd.value),
  })
    .then((res) => {
      tip.success(res.message);
      let token = res.data;
      setLocalToken(token);
      router.push({ name: "Room", query: { usr: u_name.value } });
    })
    .catch((err) => {
      tip.error("账号密码错误!");
    });
};

密钥分配——使用Keytool

参考教程 https://blog.csdn.net/m0_59579040/article/details/124811147

keytool 是个密钥和证书管理工具。它使用户能够管理自己的公钥/私钥对及相关证书,用于(通过数字签名)自我认证(用户向别的用户/服务认证自己)或数据完整性以及认证服务。它还允许用户储存他们的通信对等者的公钥(以证书形式)。

在计算机网络上,OpenSSL是一个开放源代码的软件库包,应用程序可以使用这个包来进行安全通信,避免窃听,同时确认另一端连接者的身份。这个包广泛被应用在互联网的网页服务器上。

通过如下步骤可以产生证书和公钥

keytool -genkeypair -storetype PKCS12 -alias yjq - -keyalg RSA -keysize 1024 -dname "CN=xxx, OU=xxx, O=xxx, L=xx, ST=xx, C=CN" -keystore D:\mygit\大三下笔记\网安课设\safechat-server\src\main\resources\keys-and-certs\yjq.keystore -keypass 123456 -storepass 123456 -validity 36500 -v  

产生二进制文件yjq.keystore,以上部分可由脚本生成。

经过KeyStore的相关操作生成公钥、证书和私钥

safechat,# 计算机网络安全与管理,安全,web安全,java

当用户需要公钥和私钥时,只需要调用相关方法即可。

public static void genKeyPair(String name) throws Exception {  
    //以 PKCS12 规格,创建 KeyStore  
    KeyStore keyStore = KeyStore.getInstance("PKCS12");  
    path = "keys-and-certs/" + name + ".keystore";  
    //载入 jks 和该 jks 的密码 到 KeyStore 内  
    keyStore.load(new FileInputStream(new ClassPathResource("keys-and-certs/yjq.keystore").getFile()), "123456".toCharArray());  
  
    // 要获取 key,需要提供 KeyStore 的别名 和该 KeyStore 的密码  
    // 获取 keyStore 内所有别名 alias  
    Enumeration<String> aliases = keyStore.aliases();  
    String alias = null;  
    alias = aliases.nextElement();  
    char[] keyPassword = "123456".toCharArray();  
    keyPairString.clear();  
    //私钥  
    privateKey = (PrivateKey) keyStore.getKey(alias, keyPassword);  
    keyPairString.put("PR", new String(Base64.getEncoder().encode(privateKey.getEncoded())));  
    //证书  
    Certificate certificate = keyStore.getCertificate(alias);  
    //公钥  
    publicKey = certificate.getPublicKey();  
    keyPairString.put("PU", new String(Base64.getEncoder().encode(publicKey.getEncoded())));  
  
} 

使用公钥加密保证消息认证和机密性

参考教程https://blog.csdn.net/m0_59579040/article/details/124811147.

A和B进行通信,首先使用A的私钥对报文M进行加密——数字签名;然后A用B的公钥对上述结果进行加密——保证了保密性。

B收到消息后,用B的私钥解密,再用A的公钥验证签名。

safechat,# 计算机网络安全与管理,安全,web安全,java

这里我使用RSA作为加密算法、SHA1WithRSA作为签名算法,签名和加密的操作实现在类RSAUtils.java中。

签名
/** 
* 私钥签名 
* @param content 字符串 
* @param priKey 私钥 
* @return 
* @throws Exception 
*/  
public static byte[] sign(String content, PrivateKey priKey) throws Exception {  
    Signature signature = Signature.getInstance(SIGALG);  
    signature.initSign(priKey);  
    signature.update(content.getBytes());  
    return signature.sign();  
}  
  
/** 
* 公钥验证签名 
* @param content 字符串 
* @param sign 签名 
* @param pubKey 公钥 
* @return 身份是否真实 
* @throws Exception 
*/  
public static boolean verify(String content, byte[] sign, PublicKey pubKey) throws Exception {  
  
    Signature signature = Signature.getInstance(SIGALG);  
    signature.initVerify(pubKey);  
    signature.update(content.getBytes());  
    return signature.verify(sign);  
}  

加密解密
/** 
* RSA公钥加密 
* 
* @param content       加密字符串 
* @param publicKey 公钥 
* @return 密文 
* @throws Exception 加密过程中的异常信息 
*/  
public static String encrypt(String content, String publicKey) throws Exception {  
    //base64编码的公钥  
    byte[] decoded = Base64.getMimeDecoder().decode(publicKey);  
    RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(KEYALG).generatePublic(new X509EncodedKeySpec(decoded));  
    System.out.println(pubKey.getAlgorithm());  
    //RSA加密  
    Cipher cipher = Cipher.getInstance(KEYALG);  
    cipher.init(Cipher.ENCRYPT_MODE, pubKey);  
    String outStr = Base64.getEncoder().encodeToString(cipher.doFinal(content.getBytes("UTF-8")));  
    return outStr;  
}  
  
/** 
* RSA私钥解密 
* 
* @param content        加密字符串 
* @param privateKey 私钥 
* @return 明文 
* @throws Exception 解密过程中的异常信息 
*/  
public static String decrypt(String content, String privateKey) throws Exception {  
  
    //64位解码加密后的字符串  
    byte[] inputByte = Base64.getMimeDecoder().decode(content);  
    //        //base64编码的私钥  
    byte[] decoded = Base64.getMimeDecoder().decode(privateKey);  
    RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));  
    //RSA解密  
    Cipher cipher = Cipher.getInstance("RSA");  
    cipher.init(Cipher.DECRYPT_MODE, priKey);  
    String outStr = new String(cipher.doFinal(inputByte));  
    return outStr;  
}  

使用AES加密消息

因为公钥加密的消息认证比较费时间,所以当两个用户建立消息通信时由一方产生会话密钥,使用公钥加密来传送会话密钥并认证身份。身份认证完成后,使用该会话密钥加密消息,其中使用对称加密技术AES加密消息。

消息报文格式如下:

1、 id:报文标识id;

2、 time:报文发送时间

3、 content:报文内容(加密)

4、 type:报文类型:会话密钥消息/公钥消息

5、 sender_name:发送者

6、 receiver_name:接收者

7、 sign:发送者签名。

加密过程如下:

public final class AESUtils{  
    private static final String ALGORITHM = "AES";  
    public static String genAesSecret(){  
        try {  
            KeyGenerator kg = KeyGenerator.getInstance("AES");  
            //下面调用方法的参数决定了生成密钥的长度,可以修改为128, 192或256  
            kg.init(256);  
            SecretKey sk = kg.generateKey();  
            byte[] b = sk.getEncoded();  
            String secret = Base64.encodeBase64String(b);  
            return secret;  
        }  
        catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
            throw new RuntimeException("没有此算法");  
        }  
    }  
    /** 
     * 根据密钥对指定的明文plainText进行加密. 
     * 
     * @param plainBytes 明文 
     * @param keyBytes   密码 
     * @return 加密后的密文. 
     * @since 0.0.8 
     */  
    public static byte[] encrypt(byte[] plainBytes, byte[] keyBytes) {  
        try {  
            SecretKey secretKey = getSecretKey(keyBytes);  
            Cipher cipher = Cipher.getInstance(ALGORITHM);  
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);  
            return cipher.doFinal(plainBytes);  
        } catch (Exception e) {  
            throw new RuntimeException(e);  
        }  
    }  
  
    /** 
     * 根据密钥对指定的密文 cipherBytes 进行解密. 
     * 
     * @param cipherBytes 加密密文 
     * @param keyBytes    秘钥 
     * @return 解密后的明文. 
     * @since 0.0.8 
     */  
    public static byte[] decrypt(byte[] cipherBytes, byte[] keyBytes) {  
        try {  
            SecretKey secretKey = getSecretKey(keyBytes);  
  
            Cipher cipher = Cipher.getInstance(ALGORITHM);  
            cipher.init(Cipher.DECRYPT_MODE, secretKey);  
            return cipher.doFinal(cipherBytes);  
        } catch (Exception e) {  
            throw new RuntimeException(e);  
        }  
    }  
  
    /** 
     * 获取加密 key 
     * @param keySeed seed 
     * @return 结果 
     * @since 0.0.8 
     */  
    private static SecretKey getSecretKey(byte[] keySeed) {  
        try {  
            // 避免 linux 系统出现随机的问题  
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); 
            secureRandom.setSeed(keySeed);  
            KeyGenerator generator = KeyGenerator.getInstance("AES");  
            generator.init(secureRandom);  
            return generator.generateKey();  
        } catch (Exception e) {  
            throw new RuntimeException(e);  
        }  
    }  
}  

服务端加密

结合RSA与AES的加密如下:

先用公钥加密RSA发送对称加密使用的会话密钥,然后再用会话密钥进行AES对称加密通信。

 // 监听客户端发送消息  
socketIOServer.addEventListener(Constants.EVENT_MESSAGE_TO_SERVER, String.class, (client, data, ackSender) -> {  
    String sender_name = getParamsByClient(client, "u_name");  
    ObjectMapper mapper = new ObjectMapper();  
    Message message = mapper.readValue(data, Message.class);  
    String receiver_name = message.getReceiver_name();  
  
    if (message.getType().equals(Constants.MASTER_MESSAGE)) {  
        //使用公钥加密传送会话密钥  
        if (AesKey.equals("")) {  
            log.info("用户" + sender_name + "生成会话密钥");  
            AesKey = AESUtils.genAesSecret();  
            message.setContent(AesKey);  
            log.info("用户" + sender_name + "使用用户" + sender_name + "的私钥对会话密钥进行签名");  
            String sign = new String(RSAUtils.sign(message.getContent(), RSAUtils.getPrivateKey()), "ISO-8859-1");  
            message.setSign(sign);  
            String result = RSAUtils.encrypt(message.getContent(), publicKeyStringMap.get(receiver_name));  
            log.info("使用用户" + receiver_name + "的公钥对会话密钥进行加密:" + result);  
            message.setContent(result);  
            sendMessageToFriend(message.getReceiver_name(), message);  
        } else {  
            return;  
        }  
    } else {  
        //使用会话密钥发送消息  
        byte[] bytes = AESUtils.encrypt(message.getContent().getBytes(), AesKey.getBytes());  
        String encrypt = new String(bytes, "ISO-8859-1");  
        log.info("用户" + sender_name + "使用会话密钥加密消息");  
        message.setContent(encrypt);  
        sendMessageToFriend(message.getReceiver_name(), message);  
    }    
});  
//  
//GBK,  GB2312,UTF-8等一些编码方式为多字节或者可变长编码,原来的字节数组就被改变了,再转回原来的byte[]数组就会发生错误了。  
//ISO-8859-1通常叫做Latin-1,Latin-1包括了书写所有西方欧洲语言不可缺少的附加字符,其中 0~127的字符与ASCII码相同,  
// 它是单字节的编码方式,在来回切换时不会出现错误。  
  
// 监听客户端接收消息  
socketIOServer.addEventListener("receive_triger", String.class, (client, data, ackSender) -> {   
    ObjectMapper mapper = new ObjectMapper();  
    Message message = mapper.readValue(data, Message.class);  
    String sender_name = message.getSender_name();  
    String receiver_name = message.getReceiver_name();  
    if (message.getType().equals(Constants.MASTER_MESSAGE)) {  
        log.info("收到来自" + sender_name + "发送给" + message.getReceiver_name() + "的消息: " + message.getContent());  
        String result = RSAUtils.decrypt(message.getContent(), RSAUtils.getKeyPair().get("PR"));  
        log.info("用户" + receiver_name + "使用用户" + receiver_name + "的私钥对消息进行解密:");  
        message.setContent(result);  
        log.info("用户" + receiver_name + "使用用户" + sender_name + "的公钥对消息进行验证签名");  
        Boolean sign = (RSAUtils.verify(message.getContent(), message.getSign().getBytes("ISO-8859-1"), publicKeyMap.get(sender_name)));  
        if (sign) {  
            log.info("签名验证成功!身份无误");  
        } else {  
            throw new Exception("签名错误!");  
        }  
        receiveMessageFromFriend(message.getReceiver_name(), message);  
    } else {  
        log.info("收到来自" + sender_name + "发送给" + message.getReceiver_name() + "的消息: " + message.getContent());  
        String text = new String(AESUtils.decrypt(message.getContent().getBytes("ISO-8859-1"), AesKey.getBytes()), "UTF-8");  
        log.info("用户" + receiver_name + "使用会话密钥进行解密");  
        message.setContent(text);  
        receiveMessageFromFriend(message.getReceiver_name(), message);  
    }  
});

6 演示

登录

safechat,# 计算机网络安全与管理,安全,web安全,java

进入主页面

可以看到好友列表

safechat,# 计算机网络安全与管理,安全,web安全,java

同时获取本地密钥库中的公私钥并将其加入公钥库

safechat,# 计算机网络安全与管理,安全,web安全,java

选择好友进行私聊

选择好友进行私聊,进入聊天界面。

safechat,# 计算机网络安全与管理,安全,web安全,java

safechat,# 计算机网络安全与管理,安全,web安全,java

发送消息

在输入框中输入消息,点击发送,接收者和发送者的聊天框都会出现相应的消息。此消息是经过后端AES对称加密解密得到的。

safechat,# 计算机网络安全与管理,安全,web安全,java文章来源地址https://www.toymoban.com/news/detail-816760.html

到了这里,关于网络安全实验——安全通信软件safechat的设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 软件I2C通信的设计要点

    多多借助逻辑分析仪,可以快速定位和解决问题。 软件iic进行软件延时的时候, 其中使用的变量需要通过 volatile 进行修饰。 注意当从机是芯片模拟的IIC时序,从机可能由于处理反应较慢的原因, 容易出现将 总线stretch 的现象, 就是从机会一直将总线的时钟线一直拉低。例

    2024年02月09日
    浏览(38)
  • 通信算法之130:软件无线电-接收机架构

      1. 超外差式接收机    2.零中频接收机  3.数字中频接收机    

    2023年04月10日
    浏览(37)
  • 力控软件与S7-200SMART无线PPI通信

    在实际系统中,人机界面与PLC通常不在一起,中心计算机一般放置在控制室,而PLC安装在现场车间,二者之间距离往往从几十米到几千米。如果布线的话,需要挖沟施工,比较麻烦,这种情况下比较适合采用无线通信方式。因为采用无线PPI协议响应速度快且不需要编程,只需

    2024年02月10日
    浏览(28)
  • STM32单片机初学4-IIC通信(软件模拟)

    IIC ( Inter-Integrated Circuit )又称I2C(习惯读“I方C”),是 IIC Bus简称,中文名为 集成电路总线 ,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。适用于IC间的短距离数据传输。 最初的IIC通信速

    2024年02月05日
    浏览(52)
  • STM32软件模拟IIC时序实现与EEPROM的通信

                       IIC简介  IIC物理层 用软件模拟IIC时序         一、空闲状态(初始化):SCL 和SDA都保持高电平         二、开始信号 :SCL为高电平期间,SDA由高电平变为低电平。         三、停止信号:SCL为高电平期间,SDA由低电平变为高电平   

    2024年02月09日
    浏览(69)
  • 【AUTOSAR】软件架构中的接口设计与跨核通信解析

    目录 前言 一、什么是接口? 二、什么是CS接口?什么是SR接口?区别是什么?

    2024年02月03日
    浏览(34)
  • 网络安全实验——web安全

    目录 实验目的 实验原理 实验内容 实验1 1. 地址栏中执行脚本 2. 对DOM技术的利用 实验2  1.jump1 2.jump2 3.get 4.xss 5.注册bss 6.盗取cookie 7.分析cookie  实验3 一.搭建IIS服务器 二.身份验证和权限设置 三.IP地址和域名限制 四.安全通信 五. 单点登录  实验总结 1. 了解什么是XSS 2. 掌握盗

    2024年02月13日
    浏览(39)
  • [Ubuntu 20.04 PC] 安装C-Kermit:一个开源串口通信软件

    在计算机科学领域,串口通信一直是非常重要的一环。而C-Kermit作为一款强大而灵活的开源串口通信软件,广泛应用于UNIX、Linux和Windows等操作系统中。本文将介绍C-Kermit的基本原理、特点以及如何使用它进行串口通信。 C-Kermit是由C语言实现的,旨在提供可靠、高效的串口通信

    2024年02月11日
    浏览(30)
  • Modbus通信协议介绍以及Modbus Poll、Slave软件使用介绍

    Modbus Slave是一个模拟Modbus协议从机的上位机软件,主要用于模拟测试跟其他主机设备通信的过程。与之成套存在的另一个软件--Modbus Poll,则是模拟Modbus协议主机的上位机软件。该软件内部封装Modbus协议,通过图形化界面使得操作更为简单。软件支持ModbusRTU、ASCII、TCP/IP协议。

    2024年02月09日
    浏览(33)
  • 手机电脑scoket通信 手机软件 APP inventor 服务端程序python

    再帮助同学坐课题的时候接触到了scoket通信,了解到这应该是基层网络通信的原理,于是就导出搜索了一下相关的资料,简单来说scoket通信就是,可以让不同设备在同一个网络环境的条件下,可以实现相互通信既可以一对一也可以一对多,总之这对开发者来说,是跨设备交互

    2024年02月10日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包