关于Java对接网络验证+实践小例子,简单易懂

一个简单的网络验证小例子,各位大佬勿喷

        突发奇想,如果一位A友找你拿一份 Working Fruits,但是你不想这位A友把你辛苦劳作、熬夜加点写出的代码分享他或她的另外一位朋友B友,也许并不是很有价值的一个小作业而已,但是就像我一样,多多少少有着私心的幼稚心理。这种想法就像你下载一个收费软件一样,所属权是你,需要授权码或者特定的方式得到你的允许,才能够运行整体代码。当然,不要破环人与人之间的关系或情感,学习为本(说笑了),教程只提供参考。 


目录

一. 预备知识点

二. 常见的网络验证   

三. 微验验证原理

四. 代码实现

五. 缺陷与优化


一. 预备知识点

        我们需要了解MD5和RC4加密原理。MD5是一种常用的哈希算法,它可以将任意长度的数据转换为固定长度的哈希值。通过对比哈希值,我们可以验证数据的完整性和一致性。而RC4是一种流密码算法,它可以根据密钥生成伪随机流,用于对数据进行加密和解密。通过使用MD5和RC4加密算法,我们可以确保在网络传输过程中的数据安全性。

        其次,我们需要了解Java反射。Java反射是一种强大的机制,它允许我们在运行时动态地获取类的信息并操作类的成员。在网络验证中,我们可以利用Java反射机制来动态加载和调用验证相关的类和方法(写好了就包装成一个JAR吧),从而实现灵活的验证逻辑。

        当然,网络验证的实现涉及到更多的知识和技术,比如数据库的构建和管理,有自己的服务器自己管理数据,自主随时管理数据,但是表数据的增删改查操作会产生更多的工作量。这些都是我们在实际开发中需要考虑的问题,需要具备相应的知识储备和技能因此,我们不如简单点,用别人写好的验证系统,直接拿来用不就是了,代码越简单越好对吧

        在实际的网络验证中,我们可以借助已有的对接API来实现本地的验证。这意味着我们可以选择市面上已有的验证服务或库,并通过网络接口进行数据传输和验证。通过使用这些对接API,我们可以简化验证的实现过程,提高开发效率。      

二. 常见的网络验证   

        在网络验证领域中,可以找到一些常见的验证案例,如T3、BS、易游、微验、大纸片等验证系统。这些系统各有特点,其中T3验证系统相对容易被破解,易游验证系统在外观上更加简单,但内部却更为复杂。考虑到教程的讲解需要,我们选择使用微验验证管理系统来进行讲解。

        微验验证管理系统以其独特的特点和功能而备受易语言开发者关注。它提供了一种简单而高效的验证解决方案,适用于各种场景和需求。通过微验验证管理系统,确保验证的安全性和可靠性。

        相比于其他验证系统,微验验证管理系统在设计上更加注重用户体验和易用性。它采用了简化的外观设计,使用户能够快速上手并进行验证操作。同时,微验验证管理系统内部的复杂性也为用户提供了更多的灵活性和定制化选项。

        本教程将重点介绍如何使用微验验证管理系统进行验证操作。通过详细的讲解和示例,本教程将帮助自身了解验证的基本原理和操作步骤。读者可以学习如何配置和管理微验验证系统,以及如何应用验证功能到项目中。

三. 微验验证原理

        先不管加密如何加密,解密如何解密,搞清楚这个验证流程,话不多说,看图。

四. 代码实现

        官方提供的Java对接例子只有不能就地运行、同时客户端不具有安卓特定的imei码,否则验证无法过签名,需要实际开发打包成APP才可使用,因此,我二改了官方提供的代码,可以就地运行。

        微验官方已经写好的rc4加密解密方法,可直接使用

        需要具体看懂吗,不需要,只需要明白每个方法的作用,具体怎么实现的不重要,我还是更喜欢面向对象

        RC4加密算法工具类详解

  1. encryRC4String方法:将给定的字符串数据使用RC4算法进行加密,并返回加密后的十六进制字符串形式。参数包括待加密的数据、密钥和字符集。

  2. encryRC4Byte方法:将给定的字符串数据使用RC4算法进行加密,并返回加密后的字节数组形式。参数包括待加密的数据、密钥和字符集。

  3. decryRC4方法:将给定的十六进制字符串数据使用RC4算法进行解密,并返回解密后的字符串形式。参数包括待解密的数据、密钥和字符集。

  4. initKey方法:根据给定的密钥生成RC4算法所需的初始密钥。返回一个字节数组。

  5. bytesToHex方法:将字节数组转换为十六进制字符串形式。返回转换后的字符串。

  6. hexToByte方法:将十六进制字符串转换为字节数组形式。返回转换后的字节数组。

  7. RC4Base方法:根据给定的输入数据和密钥使用RC4算法进行加密或解密操作。返回加密或解密后的字节数组。

     属性KEK 特定的密钥,不同的密钥产生不同的结果,不可更改

        RC4工具类 

import java.io.UnsupportedEncodingException;

public class RC4Util {
    public static final String KEY = "PZ8KBd4TbE7mjEb";

    public RC4Util() {
    }

    public static String encryRC4String(String data, String key, String chartSet) throws UnsupportedEncodingException {
        return data != null && key != null ? bytesToHex(encryRC4Byte(data, key, chartSet)) : null;
    }

    public static byte[] encryRC4Byte(String data, String key, String chartSet) throws UnsupportedEncodingException {
        if (data != null && key != null) {
            byte[] bData;
            if (chartSet != null && !chartSet.isEmpty()) {
                bData = data.getBytes(chartSet);
                return RC4Base(bData, key);
            } else {
                bData = data.getBytes();
                return RC4Base(bData, key);
            }
        } else {
            return null;
        }
    }

    public static String decryRC4(String data, String key, String chartSet) throws UnsupportedEncodingException {
        return data != null && key != null ? new String(RC4Base(hexToByte(data), key), chartSet) : null;
    }

    private static byte[] initKey(String aKey) {
        byte[] bkey = aKey.getBytes();
        byte[] state = new byte[256];

        int index1;
        for(index1 = 0; index1 < 256; ++index1) {
            state[index1] = (byte)index1;
        }

        index1 = 0;
        int index2 = 0;
        if (bkey.length == 0) {
            return null;
        } else {
            for(int i = 0; i < 256; ++i) {
                index2 = (bkey[index1] & 255) + (state[i] & 255) + index2 & 255;
                byte tmp = state[i];
                state[i] = state[index2];
                state[index2] = tmp;
                index1 = (index1 + 1) % bkey.length;
            }

            return state;
        }
    }

    public static String bytesToHex(byte[] bytes) {
        StringBuffer sb = new StringBuffer();

        for(int i = 0; i < bytes.length; ++i) {
            String hex = Integer.toHexString(bytes[i] & 255);
            if (hex.length() < 2) {
                sb.append(0);
            }

            sb.append(hex);
        }

        return sb.toString();
    }

    public static byte[] hexToByte(String inHex) {
        int hexlen = inHex.length();
        byte[] result;
        if (hexlen % 2 == 1) {
            ++hexlen;
            result = new byte[hexlen / 2];
            inHex = "0" + inHex;
        } else {
            result = new byte[hexlen / 2];
        }

        int j = 0;

        for(int i = 0; i < hexlen; i += 2) {
            result[j] = (byte)Integer.parseInt(inHex.substring(i, i + 2), 16);
            ++j;
        }

        return result;
    }

    private static byte[] RC4Base(byte[] input, String mKkey) {
        int x = 0;
        int y = 0;
        byte[] key = initKey(mKkey);
        byte[] result = new byte[input.length];

        for(int i = 0; i < input.length; ++i) {
            x = x + 1 & 255;
            y = (key[x] & 255) + y & 255;
            byte tmp = key[x];
            key[x] = key[y];
            key[y] = tmp;
            int xorIndex = (key[x] & 255) + (key[y] & 255) & 255;
            result[i] = (byte)(input[i] ^ key[xorIndex]);
        }

        return result;
    }
}

        接下来是通过官方提供的加密工具类自主写的对接例子类,可以通过上文中的验证流程图共同参考。

        WeiYan对接类

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Enumeration;
import java.util.Random;

//TODO:Benmao

public class WeiYan {
    String kami;//卡密
    public String markcode;//设备码
    public long time;//时间戳//Long time = System.currentTimeMillis()
    public String appKey="57012";//不可更改
    //"kami="+卡密+"&markcode="+设备码+"&t="+时间戳+"&"+sss.APPKEY
    public String data;
    public String SIGN;//通过md5加密
    public int random;//随机数,范围[1000, 9999]

    public String url="https://wy.llua.cn/api/?id=kmlogon"+"&app="+this.appKey+"&data=";

    //加密字段MD5
    public void Gm(String kami){
        this.kami=kami;
        this.time=System.currentTimeMillis()/1000;//Long.parseLong(String.valueOf(System.currentTimeMillis()).substring(0 ,10))

        this.markcode=getDeviceID();//getDeviceID();
        //需要加密的字段
        String str="kami="+this.kami+"&markcode="+this.markcode+"&t="+this.time+"&"+this.appKey;
        this.SIGN = stringToMD5(str);//encodeMD5(str);
    }

    //Rce4字段加密
    public void GD(){
        //随机数
        this.random=new Random().nextInt(99999)+1000;//范围1000~9999
        //需要加密的字段
        String str="kami="+this.kami+"&markcode="+this.markcode+"&t="+this.time+"&sign="+this.SIGN+"&value"+this.time+this.random;
        try {
            this.data=RC4Util.encryRC4String(str, RC4Util.KEY, "UTF-8");
            url+=this.data;
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    //返回数据解密
    public String deRec4(String anUrl){
        //String anUrl = "https://wy.llua.cn/api/?id=kmlogon&app=57012&data=4a5311e1cf22abb6c079de314f7f7ca9670658e0d306b87a9ab62f560e75ec31cdb0598abc2df00063003484e229ee81d0e07daf64b6d8a4cd190835bdf0c8bbd329b901888296a9a376c9bd73e62f56bce31982e072a38f8fb1fc261d43ce7231edf7c7a883bfec92c47475f0a07e3045161fcc10e5";
        URL url = null;
        String res ="";//最终结果
        try {
            url = new URL(anUrl);
            URLConnection conn = url.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String inputLine;
            StringBuilder result = new StringBuilder();
            while ((inputLine = in.readLine()) != null) {
                result.append(inputLine);
            }
            //System.out.println(result);//加密前的字段
            res=result.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        //解码
        try {
            String json = RC4Util.decryRC4(res, RC4Util.KEY, "UTF-8");
            return json;
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }


    //MD5加密
    public static String encodeMD5(String str)
    {
        try
        {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(str.getBytes("UTF-8"));
            byte messageDigest[] = md5.digest();
            StringBuilder hexString = new StringBuilder();
            for (byte b : messageDigest)
            {
                hexString.append(String.format("%02X", b));
            }
            return hexString.toString().toLowerCase();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return "";
    }

    //iApp Md5加密
    public static String stringToMD5(String plainText)
    {
        byte[] secretBytes = new byte[0];
        try {
            secretBytes = MessageDigest.getInstance("md5").digest(plainText.getBytes());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        String md5code = new BigInteger(1, secretBytes).toString(16);
        for(int i = 0; i < 32 - md5code.length(); i++)
        {
            md5code = "0" + md5code;
        }
        return md5code;
    }

    //获取独立设备码
    public static String getDeviceID() {
        try {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                byte[] mac = networkInterface.getHardwareAddress();
                if (mac != null) {
                    StringBuilder sb = new StringBuilder();
                    for (byte b : mac) {
                        sb.append(String.format("%02X", b));
                    }
                    return sb.toString().toLowerCase();
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return null;
    }
}

RC4加密算法工具类详解 

  1. Gm方法:对卡密进行加密处理,生成设备码和时间戳,并计算签名。参数为卡密。

  2. GD方法:对需要加密的字段进行RC4加密,并生成随机数。参数为卡密。

  3. deRec4方法:对返回的数据进行解密处理。参数为需要解密的URL。

  4. encodeMD5方法:对字符串进行MD5加密处理。参数为待加密的字符串。

  5. stringToMD5方法:对字符串进行MD5加密处理,并返回加密后的结果。参数为待加密的字符串。

  6. getDeviceID方法:获取设备的唯一标识码。

  7. kami(卡密)、markcode(设备码)、time(时间戳)、appKey(应用密钥)、data(加密后的数据)、SIGN(签名)、random(随机数)和url(请求的URL)。

    public String getKami() {
        return kami;
    }

    public void setKami(String kami) {
        this.kami = kami;
    }

    public String getMarkcode() {
        return markcode;
    }

    public void setMarkcode(String markcode) {
        this.markcode = markcode;
    }

    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time = time;
    }

    public String getAppKey() {
        return appKey;
    }

    public void setAppKey(String appKey) {
        this.appKey = appKey;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public String getSIGN() {
        return SIGN;
    }

    public void setSIGN(String SIGN) {
        this.SIGN = SIGN;
    }

    public int getRandom() {
        return random;
    }

    public void setRandom(int random) {
        this.random = random;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

        接下来就是写一个验证例子。上述代码编译成一个jar包,然后使用反射调用其内部方法

         Main类

/**
 * @作者:笨猫
 * @create: 2024-03-16 14:52
 **/
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class main {
    public static void main(String[] args) {
        String kami = "Benmao2127FC";//这个就是卡密

        try {
            // 反射调用 WeiYan()构造方法,输出this.url
            Class<?> weiYanClass = Class.forName("top.benmao.rc4.WeiYan");
            Constructor<?> weiYanConstructor = weiYanClass.getConstructor();
            Object weiYanObject = weiYanConstructor.newInstance();
            Method getUrlMethod = weiYanClass.getDeclaredMethod("getUrl");
            getUrlMethod.setAccessible(true);
            String url = (String) getUrlMethod.invoke(weiYanObject);
            System.out.println("this.url: " + url);

            // 反射调用Gm方法,并输出属性this.SIGN
            Method gmMethod = weiYanClass.getDeclaredMethod("Gm", String.class);
            gmMethod.setAccessible(true);
            gmMethod.invoke(weiYanObject, kami);
            String sign = (String) weiYanClass.getField("SIGN").get(weiYanObject);
            System.out.println("this.SIGN: " + sign);

            // 反射调用GD方法,再次输出this.url
            Method gdMethod = weiYanClass.getDeclaredMethod("GD");
            gdMethod.setAccessible(true);
            gdMethod.invoke(weiYanObject);
            url = (String) getUrlMethod.invoke(weiYanObject);
            System.out.println("this.url: " + url);

            // 反射调用deRec4()方法,获取返回值并输出
            Method deRec4Method = weiYanClass.getDeclaredMethod("deRec4", String.class);
            deRec4Method.setAccessible(true);
            String result = (String) deRec4Method.invoke(weiYanObject, url);
            System.out.println("Result: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

        运行结果

        只需要把获取的结果JSON后进入校验即可,剩下的就看自己怎么运用吧。

五. 缺陷与优化

        想说的是,比起官方提供的代码,就地运行只需要懂一点点Java语言,有可能解密就只是一个变量的事情,如果需要更加安全、高效、易处理的工作方式,可以继续尝试包装成一个apk并选择各大官方的加固平台进行加固,如360加固。

        本次教程结束了,感兴趣的可以关注我,如有与本博客持有不同的看法或评判,请随时留意吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/479354.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

draw.io 去除箭头

问题 draw.io 去除箭头 详细问题 笔者使用draw.io绘制流程图&#xff0c;需要没有箭头的连接器&#xff0c;但是General所提供的连接器添加了尾部箭头&#xff0c;如何取消尾部箭头? 解决方案 1、点击选中选择连接器&#xff08;箭头1&#xff09;。在格式面板的“Style…

45.i++和++i

目录 一.基本概念 二.区别 三.总结 四.视频教程 一.基本概念 i和i两者的作用都是自增加1。单独使用的话&#xff0c;i和i&#xff0c;效果都是一样的&#xff0c;就是ii1。 int main() {int i 0;i; } int main() {int i 0;i; } 最后的结果都是1。 二.区别 如上单独使…

操作系统系列学习——内存使用与分段

文章目录 前言内存使用与分段 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招&#xff0c;计划学习操作系统并完成6.0S81&#xff0c;加油&#xff01; 本文总结自B站【哈工大】操作系统 李治军&#xff08;全32讲&#xff09; 老师课程讲的非常好&#xff0c;感谢 【哈工…

MySQL中Buffer pool、Log Buffer和redo、undo日志介绍

MySQL中Buffer pool、Log Buffer和redo、undo日志介绍 Buffer Pool 原理MySQL中的内存结构Buffer PoolChange BufferLog Buffer redo和undo日志redo日志为什么需要REDO日志redo log 基本概念redo的组成redo的整体流程redo log的刷盘策略 undo 日志undo log 基本概念undo log的作…

Linux:网络相关概念的认识

文章目录 基本认知数据跨网络传输初识ip地址 端口号端口号的理解进程与端口号总结 本篇是基于前面对于网络的基本框架搭建&#xff0c;进而进行相关概念的进一步理解&#xff0c;为后续准备 基本认知 那么首先总结一下一些基本的相关结论性的信息 对于任何协议来说&#xff…

156.乐理基础-和弦固定标记法(五)挂留(sus)和弦省略音(omit)和弦

如果到这五线谱还没记住还不认识的话去看102.五线谱-高音谱号与103.五线谱-低音谱号这两个里&#xff0c;这里面有五线谱对应的音名&#xff0c;对比着看 如果一章没落下&#xff0c;看到这里&#xff0c;但是看不懂什么意思&#xff0c;那就强行下看&#xff0c;看着看着指不…

热点!浅谈低代码到底是什么?

低代码平台的历史相对较短&#xff0c;大约始于 2000 年初&#xff0c;源于快速应用程序开发工具。随着低代码平台和工具的日益普及和优势&#xff0c;它不断发展以满足各种领域和角色的需求。 本文将研究各种低代码和无代码应用程序开发方法、业务用例、挑战和未来预测等。 …

定制红酒:品质保障,从源头做起

云仓酒庄的洒派定制红酒&#xff0c;以其卓着的品质和与众不同的口感&#xff0c;赢得了众多消费者的喜爱。而这种品质的保障&#xff0c;正是从源头上开始的。 在葡萄种植方面&#xff0c;种植者对土壤、气候等自然条件进行严格的筛选和评估&#xff0c;确保葡萄能够在理想的环…

递增四元组

解法&#xff1a; 首先都可以想到dp[i]&#xff1a;第i个元素结尾的递增四元组有dp[i]个 然后发现有一组数据&#xff1a;2,3,6,1,5,8。会出现6结尾和5结尾的递增三元组&#xff0c;也就是未来的决策受过去影响&#xff0c;专业的说就是有后效性。需要强化约束条件&#xff0…

普发Pfeiffer分子泵TMH-U1001PC-1601PC安装使用维护说明

普发Pfeiffer分子泵TMH-U1001PC-1601PC安装使用维护说明

【Linux中vim系列】如何在vim中检索字符串

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

最简明的大模型agent教程

大模型相关目录 大模型&#xff0c;包括部署微调prompt/Agent应用开发、知识库增强、数据库增强、知识图谱增强、自然语言处理、多模态等大模型应用开发内容 从0起步&#xff0c;扬帆起航。 大模型应用向开发路径及一点个人思考大模型应用开发实用开源项目汇总大模型问答项目…

关闭Elasticsearch built-in security features are not enabled

禁用Kibana安全提示&#xff08;Elasticsearch built-in security features are not enabled&#xff09; Kibana提示#! Elasticsearch built-in security features are not enabled. Without authentication, your cluster could be accessible to anyone. See https://www.e…

基于SSM+Jsp+Mysql的KTV点歌系统

基于SSMJspMysql的KTV点歌系统 基于SSMJspMysql的KTV点歌系统的设计与实现 开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工…

Redisson分布式锁(WatchDog分析,浅浅看下源码)

带大家简单了解下Redisson的看门狗机制&#xff0c;这个面试中也比较常见。 目录 WatchDog&#xff08;看门狗&#xff09;机制开启WatchDog&#xff08;看门狗&#xff09;浅看下源码 WatchDog&#xff08;看门狗&#xff09;机制 Redisson看门狗机制是用于解决在业务运行时间…

弱网测试利器 - Charles工具实战分享!

一&#xff1a;弱网测试要点 二&#xff1a;利用抓包工具charles进行弱网设置&#xff0c;适用PC端和移动端&#xff08;IOS&#xff0f;Android&#xff09; 1、以charles 4.5.6版本为例&#xff0c;打开Proxy->Throttle Settings 2、打开Throttle Settings&#xff0c;界面…

蓝桥杯练习06给网页化个妆

给页面化个妆 介绍 各个网站都拥有登录页面&#xff0c;设计一个界面美观的登录页面&#xff0c;会给用户带来视觉上的享受。本题中我们要完成一个登录页面的布局。 准备 开始答题前&#xff0c;需要先打开本题的项目代码文件夹&#xff0c;目录结构如下&#xff1a; 其中&…

A7680C 4G模块连接MQTT服务器

AT\r\n检查模块正常工作 返回 OK ATCPIN?\r\n检查SIM是否正常 返回&#xff1a; [20:01:31.561]接收←ATCPIN? CPIN: READY OK ATCGREG? //检查网络注册注册状态 返回 [20:02:21.042]接收←ATCGREG?…

28 OpenCV 轮廓周围绘制图形

文章目录 approxPolyDP 轮廓周围绘制矩形boundingRectminAreaRect绘制圆和椭圆示例 approxPolyDP 轮廓周围绘制矩形 approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)curve&#xff1a;输入点集&#xff0c;二维点向量的集合appro…

干货!Python正则表达式之匹配分组和其他功能函数

1.匹配分组 ()&#xff1a;表示一个整体&#xff0c;表示分组&#xff0c;然后捕获 2.匹配分组实例 # 导入re模块 import re ​ tel "0755-98776754" ​ # 定义正则表达式 pattern "(\\d{4})-(\\d{8})" result re.search(pattern, tel) print(result…