推广 热搜: csgo  vue  angelababy  2023  gps  新车  htc  落地  app  p2p 

java加密解密:java md5加密后解密

   2023-05-15 网络整理佚名1640
核心提示:对称加密解密非对称加密解密对称加密:双方使用的同一个密钥,既可以加密又可以解密,这种加密方法称为对称加密,也称为单密钥加密。非对称加密:一对密钥由公钥和私钥组成(可以使用很多对密钥)。私钥解密公钥加密数据,公钥解密私钥加密数据(私钥公钥可以互相加密解密)。在非对称加密算法中常用的算法有:使用最广泛的是RSA算法,Elg

Java常用加密解密不可逆加密介绍

应用场景

一致性验证

MD5可以为文件传输场景提供文件一致性校验。

例如,文件服务器预先提供一个MD5校验值。 用户下载文件后,使用MD5算法计算下载文件的MD5校验值(任何人对文件进行修改,文件的MD5值都会改变),然后通过校验两个校验值是否一致一致,则可以判断下载的文件是否有误,或者下载的文件是否被篡改。

现在,利用MD5算法进行文件校验的方法已经广泛应用于软件下载站点、论坛数据库、系统文件安全等领域。

电子签名

MD5的一个典型应用是为一条信息(Message)生成消息摘要(Message-Digest),防止这条信息被篡改。

比如在“readme.txt”文件中写入一些内容,然后对该文件进行MD5计算,生成一个MD5值并记录下来,然后就可以将该文件发送给其他人了。 如果别人修改了“readme.txt”文件中的任何内容,当我们重新计算这个文件的MD5时,就会发现这两个MD5值是不一样的。

在上述过程中,如果涉及到另外的第三方认证机构,那么使用MD5也可以防止文档作者的“抵赖”,即所谓的数字签名应用。

安全访问认证

MD5还广泛应用于操作系统的登录认证,如Unix、各种BSD操作系统的登录密码、数字签名等诸多方面。

例如java加密解密,在Unix操作系统中,用户的密码经过MD5(或其他类似算法)计算后存储在文件系统中。 当用户登录时,系统对用户输入的密码进行MD5计算,然后与文件系统中存储的MD5值进行比较,判断用户输入的密码是否正确。 通过这些步骤,操作系统可以在不知道用户密码明文的情况下判断用户登录系统的合法性,可以防止用户密码被具有系统管理员权限的用户窃取。

MD5将任意长度的“字符串”映射为128bit的“字符串”,很难通过128bit的“字符串”推导出原始字符串。 也就是说,即使看到了源程序和算法说明,也很难将一个MD5值转换回原来的字符串。

md5的目的

java md5加密后解密_js加密 java解密_java加密解密

密码加密存储。 用户设置密码时,服务器只记录密码的MD5,不记录密码本身。 以后验证用户身份时,只需要对用户输入的密码再次进行MD5校验,然后与记录的MD5进行比对即可。 比较可以验证其密码的合法性。

数字签名,比如发布一个程序,为了防止别人在你的程序中植入病毒或者木马,你可以在发布程序的同时发布程序文件的MD5码,这样别人只需要下载对任何地方的程序做一次MD5,然后与公开的MD5进行比对,就可以知道程序是否被第三方修改过。

文件完整性验证。 比如下载一个文件,服务器返回的信息中就包含了文件的md5。 当本地下载完成后,进行md5,比较两个md5值。 如果一致,说明文件完整,没有丢包。

文件上传,比如百度云实现的二次传输,就是比较你上传的文件的md5在百度服务器上是否已经存在。 如果存在,则无需上传

MD5

package com.example.ssoserve.utils;
public class Md5 {
    //存储小组
    long []groups = null;
    //存储结果
   public String resultMessage="";
    //四个寄存器的初始向量IV,采用小端存储
    static final long A=0x67452301L;
    static final long B=0xefcdab89L;
    static final long C=0x98badcfeL;
    static final long D=0x10325476L;
    //java不支持无符号的基本数据(unsigned),所以选用long数据类型
    private long [] result={A,B,C,D};
    static final long T[][] = {
            {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
                    0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
                    0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
                    0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821},
            {0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
                    0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
                    0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
                    0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a},
            {0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
                    0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
                    0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
                    0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665},
            {0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
                    0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
                    0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
                    0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}};
    //表示X[k]中的的k取值,决定如何使用消息分组中的字
    static final int k[][] = {
            {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15},
            {1, 6,11, 0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12},
            {5, 8,11,14, 1, 4, 7,10,13, 0, 3, 6, 9,12,15, 2},
            {0, 7,14, 5,12, 3,10, 1, 8,15, 6,13, 4,11, 2, 9}};
    //各次迭代中采用的做循环移位的s值
    static final int S[][] = {
            {7,12,17,22},
            {5,9,14,20},
            {4,11,16,23},
            {6,10,15,21}};
    //4轮循环中使用的生成函数(轮函数)g
    private static long g(int i, long b, long c, long d) {
        switch (i) {
            case 0:
                return (b & c) | ((~b) & d);
            case 1:
                return (b & d) | (c & (~d));
            case 2:
                return b ^ c ^ d;
            case 3:
                return c ^ (b | (~d));
            default:
                return 0;
        }
    }
    //开始使用MD5加密
    public String start(String message){
        //转化为字节数组
        byte [] inputBytes=message.getBytes();
        //6A 61 6E 6b 69 6e 67
        //获取字节数组的长度
        int byteLen = inputBytes.length;
        //得到K值(以bit作单位的message长度)
        long K = (long)(byteLen<<3);
        //完整小组(512bit)(64byte)的个数
        int groupCount = byteLen/64;
        //分块
        for(int i = 0;i < groupCount;i++){
            //每次取512bit
            //处理一个分组
            H(divide(inputBytes, i*64));
        }
        //填充
        int rest = byteLen % 64;
        //即将填充的一个分组
        byte [] paddingBytes=new byte[64];
        //原来的尾部数据
        for(int i=0;i<rest;i++)
            paddingBytes[i]=inputBytes[byteLen-rest+i];
        //即小于448bit的情况,先填充100...0再填充K值的低64位
        //此时只会新增一个分组
        if(rest <= 56){
            //填充100...0
            if(rest<56){
                //填充10000000
                paddingBytes[rest]=(byte)(1<<7);
                //填充00000000
                for(int i=1;i<56-rest;i++) {
                    paddingBytes[rest+i]=0;
                }
            }
            //填充K值低64位
            for(int i=0;i<8;i++){
                paddingBytes[56+i]=(byte)(K&0xFFL);
                K=K>>8;
            }
            //处理分组
            H(divide(paddingBytes,0));
            //即大于448bit的情况,先填充100...0再填充K值的低64位
            //此时会新增两个分组
        }else{
            //填充10000000
            paddingBytes[rest]=(byte)(1<<7);
            //填充00000000
            for(int i=rest+1;i<64;i++) {
                paddingBytes[i]=0;
            }
            //处理第一个尾部分组
            H(divide(paddingBytes,0));
            //填充00000000
            for(int i=0;i<56;i++) {
                paddingBytes[i]=0;
            }
            //填充低64位
            for(int i=0;i<8;i++){
                //这里很关键,使用小端方式,即Byte数组先存储len的低位数据,然后右移len
                paddingBytes[56+i]=(byte)(K&0xFFL);
                K=K>>8;
            }
            //处理第二个尾部分组
            H(divide(paddingBytes,0));
        }
        //将Hash值转换成十六进制的字符串
        //小端方式!
        for(int i=0;i<4;i++){
            resultMessage += Long.toHexString(result[i] & 0xFF) +
                    Long.toHexString((result[i] & 0xFF00) >> 8) +
                    Long.toHexString((result[i] & 0xFF0000) >> 16) +
                    Long.toHexString((result[i] & 0xFF000000) >> 24);
        }
        return resultMessage;
    }
    //从inputBytes的index开始取512位,作为新的512bit的分组
    private static long[] divide(byte[] inputBytes,int start){
        //存储一整个分组,就是512bit,数组里每个是32bit,就是4字节,为了消除符号位的影响,所以使用long
        long [] group=new long[16];
        for(int i=0;i<16;i++){
            //每个32bit由4个字节拼接而来
            //小端的从byte数组到bit恢复方法
            group[i]=byte2unsign(inputBytes[4*i+start])|
                    (byte2unsign(inputBytes[4*i+1+start]))<<8|
                    (byte2unsign(inputBytes[4*i+2+start]))<<16|
                    (byte2unsign(inputBytes[4*i+3+start]))<<24;
        }
        return group;
    }
    //其实byte相当于一个字节的有符号整数,这里不需要符号位,所以把符号位去掉
    public static long byte2unsign(byte b){
        return b < 0 ? b & 0x7F + 128 : b;
    }
    // groups[] 中每一个分组512位(64字节)
    // MD5压缩函数
    private void H(long[] groups) {
        //缓冲区(寄存器)数组
        long a = result[0], b = result[1], c = result[2], d = result[3];
        //四轮循环
        for(int n = 0; n < 4; n++) {
            //16轮迭代
            for(int i = 0; i < 16; i++) {
                result[0] += (g(n, result[1], result[2], result[3])&0xFFFFFFFFL) + groups[k[n][i]] + T[n][i];
                result[0] = result[1] + ((result[0]&0xFFFFFFFFL)<< S[n][i % 4] | ((result[0]&0xFFFFFFFFL) >>> (32 - S[n][i % 4])));
                //循环轮换
                long temp = result[3];
                result[3] = result[2];
                result[2] = result[1];
                result[1] = result[0];
                result[0] = temp;
            }
        }
        //加入之前计算的结果
        result[0] += a;
        result[1] += b;
        result[2] += c;
        result[3] += d;
        //防止溢出
        for(int n = 0; n < 4 ; n++) {
            result[n] &=0xFFFFFFFFL;
        }
    }
    public static void main(String []args){
        Md5 md=new Md5();
        String message = "helloMD5";
        System.out.println("明文:" + message);
        System.out.println("小写的密文:" + md.start(message));
        System.out.println("大写的密文: " + md.resultMessage.toUpperCase());
//        明文:helloMD5
//        小写的密文:3ed9e5f6855dbcdbcd95ac6c4fe0c0a5
//        大写的密文: 3ED9E5F6855DBCDBCD95AC6C4FE0C0A5
    }
}

前端MD5

jQuery.md5.js

(function($){
    var rotateLeft = function(lValue, iShiftBits) {
        return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
    }
    var addUnsigned = function(lX, lY) {
        var lX4, lY4, lX8, lY8, lResult;
        lX8 = (lX & 0x80000000);
        lY8 = (lY & 0x80000000);
        lX4 = (lX & 0x40000000);
        lY4 = (lY & 0x40000000);
        lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
        if (lX4 & lY4) return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
        if (lX4 | lY4) {
            if (lResult & 0x40000000) return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
            else return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
        } else {
            return (lResult ^ lX8 ^ lY8);
        }
    }
    var F = function(x, y, z) {
        return (x & y) | ((~ x) & z);
    }
    var G = function(x, y, z) {
        return (x & z) | (y & (~ z));
    }
    var H = function(x, y, z) {
        return (x ^ y ^ z);
    }
    var I = function(x, y, z) {
        return (y ^ (x | (~ z)));
    }
    var FF = function(a, b, c, d, x, s, ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
    var GG = function(a, b, c, d, x, s, ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
    var HH = function(a, b, c, d, x, s, ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
    var II = function(a, b, c, d, x, s, ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
    var convertToWordArray = function(string) {
        var lWordCount;
        var lMessageLength = string.length;
        var lNumberOfWordsTempOne = lMessageLength + 8;
        var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64;
        var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16;
        var lWordArray = Array(lNumberOfWords - 1);
        var lBytePosition = 0;
        var lByteCount = 0;
        while (lByteCount < lMessageLength) {
            lWordCount = (lByteCount - (lByteCount % 4)) / 4;
            lBytePosition = (lByteCount % 4) * 8;
            lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
            lByteCount++;
        }
        lWordCount = (lByteCount - (lByteCount % 4)) / 4;
        lBytePosition = (lByteCount % 4) * 8;
        lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
        lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
        lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
        return lWordArray;
    };
    var wordToHex = function(lValue) {
        var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount;
        for (lCount = 0; lCount <= 3; lCount++) {
            lByte = (lValue >>> (lCount * 8)) & 255;
            WordToHexValueTemp = "0" + lByte.toString(16);
            WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2);
        }
        return WordToHexValue;
    };
    var uTF8Encode = function(string) {
        string = string.replace(/\x0d\x0a/g, "\x0a");
        var output = "";
        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);
            if (c < 128) {
                output += String.fromCharCode(c);
            } else if ((c > 127) && (c < 2048)) {
                output += String.fromCharCode((c >> 6) | 192);
                output += String.fromCharCode((c & 63) | 128);
            } else {
                output += String.fromCharCode((c >> 12) | 224);
                output += String.fromCharCode(((c >> 6) & 63) | 128);
                output += String.fromCharCode((c & 63) | 128);
            }
        }
        return output;
    };
    $.extend({
        md5: function(string) {
            var x = Array();
            var k, AA, BB, CC, DD, a, b, c, d;
            var S11=7, S12=12, S13=17, S14=22;
            var S21=5, S22=9 , S23=14, S24=20;
            var S31=4, S32=11, S33=16, S34=23;
            var S41=6, S42=10, S43=15, S44=21;
            string = uTF8Encode(string);
            x = convertToWordArray(string);
            a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
            for (k = 0; k < x.length; k += 16) {
                AA = a; BB = b; CC = c; DD = d;
                a = FF(a, b, c, d, x[k+0],  S11, 0xD76AA478);
                d = FF(d, a, b, c, x[k+1],  S12, 0xE8C7B756);
                c = FF(c, d, a, b, x[k+2],  S13, 0x242070DB);
                b = FF(b, c, d, a, x[k+3],  S14, 0xC1BDCEEE);
                a = FF(a, b, c, d, x[k+4],  S11, 0xF57C0FAF);
                d = FF(d, a, b, c, x[k+5],  S12, 0x4787C62A);
                c = FF(c, d, a, b, x[k+6],  S13, 0xA8304613);
                b = FF(b, c, d, a, x[k+7],  S14, 0xFD469501);
                a = FF(a, b, c, d, x[k+8],  S11, 0x698098D8);
                d = FF(d, a, b, c, x[k+9],  S12, 0x8B44F7AF);
                c = FF(c, d, a, b, x[k+10], S13, 0xFFFF5BB1);
                b = FF(b, c, d, a, x[k+11], S14, 0x895CD7BE);
                a = FF(a, b, c, d, x[k+12], S11, 0x6B901122);
                d = FF(d, a, b, c, x[k+13], S12, 0xFD987193);
                c = FF(c, d, a, b, x[k+14], S13, 0xA679438E);
                b = FF(b, c, d, a, x[k+15], S14, 0x49B40821);
                a = GG(a, b, c, d, x[k+1],  S21, 0xF61E2562);
                d = GG(d, a, b, c, x[k+6],  S22, 0xC040B340);
                c = GG(c, d, a, b, x[k+11], S23, 0x265E5A51);
                b = GG(b, c, d, a, x[k+0],  S24, 0xE9B6C7AA);
                a = GG(a, b, c, d, x[k+5],  S21, 0xD62F105D);
                d = GG(d, a, b, c, x[k+10], S22, 0x2441453);
                c = GG(c, d, a, b, x[k+15], S23, 0xD8A1E681);
                b = GG(b, c, d, a, x[k+4],  S24, 0xE7D3FBC8);
                a = GG(a, b, c, d, x[k+9],  S21, 0x21E1CDE6);
                d = GG(d, a, b, c, x[k+14], S22, 0xC33707D6);
                c = GG(c, d, a, b, x[k+3],  S23, 0xF4D50D87);
                b = GG(b, c, d, a, x[k+8],  S24, 0x455A14ED);
                a = GG(a, b, c, d, x[k+13], S21, 0xA9E3E905);
                d = GG(d, a, b, c, x[k+2],  S22, 0xFCEFA3F8);
                c = GG(c, d, a, b, x[k+7],  S23, 0x676F02D9);
                b = GG(b, c, d, a, x[k+12], S24, 0x8D2A4C8A);
                a = HH(a, b, c, d, x[k+5],  S31, 0xFFFA3942);
                d = HH(d, a, b, c, x[k+8],  S32, 0x8771F681);
                c = HH(c, d, a, b, x[k+11], S33, 0x6D9D6122);
                b = HH(b, c, d, a, x[k+14], S34, 0xFDE5380C);
                a = HH(a, b, c, d, x[k+1],  S31, 0xA4BEEA44);
                d = HH(d, a, b, c, x[k+4],  S32, 0x4BDECFA9);
                c = HH(c, d, a, b, x[k+7],  S33, 0xF6BB4B60);
                b = HH(b, c, d, a, x[k+10], S34, 0xBEBFBC70);
                a = HH(a, b, c, d, x[k+13], S31, 0x289B7EC6);
                d = HH(d, a, b, c, x[k+0],  S32, 0xEAA127FA);
                c = HH(c, d, a, b, x[k+3],  S33, 0xD4EF3085);
                b = HH(b, c, d, a, x[k+6],  S34, 0x4881D05);
                a = HH(a, b, c, d, x[k+9],  S31, 0xD9D4D039);
                d = HH(d, a, b, c, x[k+12], S32, 0xE6DB99E5);
                c = HH(c, d, a, b, x[k+15], S33, 0x1FA27CF8);
                b = HH(b, c, d, a, x[k+2],  S34, 0xC4AC5665);
                a = II(a, b, c, d, x[k+0],  S41, 0xF4292244);
                d = II(d, a, b, c, x[k+7],  S42, 0x432AFF97);
                c = II(c, d, a, b, x[k+14], S43, 0xAB9423A7);
                b = II(b, c, d, a, x[k+5],  S44, 0xFC93A039);
                a = II(a, b, c, d, x[k+12], S41, 0x655B59C3);
                d = II(d, a, b, c, x[k+3],  S42, 0x8F0CCC92);
                c = II(c, d, a, b, x[k+10], S43, 0xFFEFF47D);
                b = II(b, c, d, a, x[k+1],  S44, 0x85845DD1);
                a = II(a, b, c, d, x[k+8],  S41, 0x6FA87E4F);
                d = II(d, a, b, c, x[k+15], S42, 0xFE2CE6E0);
                c = II(c, d, a, b, x[k+6],  S43, 0xA3014314);
                b = II(b, c, d, a, x[k+13], S44, 0x4E0811A1);
                a = II(a, b, c, d, x[k+4],  S41, 0xF7537E82);
                d = II(d, a, b, c, x[k+11], S42, 0xBD3AF235);
                c = II(c, d, a, b, x[k+2],  S43, 0x2AD7D2BB);
                b = II(b, c, d, a, x[k+9],  S44, 0xEB86D391);
                a = addUnsigned(a, AA);
                b = addUnsigned(b, BB);
                c = addUnsigned(c, CC);
                d = addUnsigned(d, DD);
            }
            var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
            return tempValue.toLowerCase();
        }
    });
})(jQuery);

<script src="jquery-3.4.1.js"></script>
<script src="jQuery.md5.js"></script>
<script>
    //加密
    alert($.md5("1234"))
</script>

SHA1


public class SHA1 {
    private static final boolean hexcase = false;
    private static final String b64pad = "=";
    private static final int chrsz = 8;
    // 得到字符串SHA-1值的方法
    public static String hex_sha1(String s) {
        s = (s == null) ? "" : s;
        return binb2hex(core_sha1(str2binb(s), s.length() * chrsz));
    }
    public static String b64_hmac_sha1(String key, String data) {
        return binb2b64(core_hmac_sha1(key, data));
    }
    public static String b64_sha1(String s) {
        s = (s == null) ? "" : s;
        return binb2b64(core_sha1(str2binb(s), s.length() * chrsz));
    }
    private static String binb2b64(int[] binarray) {
        String tab = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789+/";
        String str = "";
        binarray = strechbinarray(binarray, binarray.length * 4);
        for (int i = 0; i < binarray.length * 4; i += 3) {
            int triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 0xff) << 16)
                    | (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xff) << 8)
                    | ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xff);
            for (int j = 0; j < 4; j++) {
                if (i * 8 + j * 6 > binarray.length * 32) {
                    str += b64pad;
                } else {
                    str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3f);
                }
            }
        }
        return cleanb64str(str);
    }
    private static String binb2hex(int[] binarray) {
        String hex_tab = hexcase ? "0123456789abcdef" : "0123456789abcdef";
        String str = "";
        for (int i = 0; i < binarray.length * 4; i++) {
            char a = (char) hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 0xf);
            char b = (char) hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8)) & 0xf);
            str += (new Character(a).toString() + new Character(b).toString());
        }
        return str;
    }
    private static String binb2str(int[] bin) {
        String str = "";
        int mask = (1 << chrsz) - 1;
        for (int i = 0; i < bin.length * 32; i += chrsz) {
            str += (char) ((bin[i >> 5] >>> (24 - i % 32)) & mask);
        }
        return str;
    }
    private static int bit_rol(int num, int cnt) {
        return (num << cnt) | (num >>> (32 - cnt));
    }
    private static String cleanb64str(String str) {
        str = (str == null) ? "" : str;
        int len = str.length();
        if (len <= 1) {
            return str;
        }
        char trailchar = str.charAt(len - 1);
        String trailstr = "";
        for (int i = len - 1; i >= 0 && str.charAt(i) == trailchar; i--) {
            trailstr += str.charAt(i);
        }
        return str.substring(0, str.indexOf(trailstr));
    }
    private static int[] complete216(int[] oldbin) {
        if (oldbin.length >= 16) {
            return oldbin;
        }
        int[] newbin = new int[16 - oldbin.length];
        for (int i = 0; i < newbin.length; newbin[i] = 0, i++)
            ;
        return concat(oldbin, newbin);
    }
    private static int[] concat(int[] oldbin, int[] newbin) {
        int[] retval = new int[oldbin.length + newbin.length];
        for (int i = 0; i < (oldbin.length + newbin.length); i++) {
            if (i < oldbin.length) {
                retval[i] = oldbin[i];
            } else {
                retval[i] = newbin[i - oldbin.length];
            }
        }
        return retval;
    }
    private static int[] core_hmac_sha1(String key, String data) {
        key = (key == null) ? "" : key;
        data = (data == null) ? "" : data;
        int[] bkey = complete216(str2binb(key));
        if (bkey.length > 16) {
            bkey = core_sha1(bkey, key.length() * chrsz);
        }
        int[] ipad = new int[16];
        int[] opad = new int[16];
        for (int i = 0; i < 16; ipad[i] = 0, opad[i] = 0, i++)
            ;
        for (int i = 0; i < 16; i++) {
            ipad[i] = bkey[i] ^ 0x36363636;
            opad[i] = bkey[i] ^ 0x5c5c5c5c;
        }
        int[] hash = core_sha1(concat(ipad, str2binb(data)), 512 + data.length() * chrsz);
        return core_sha1(concat(opad, hash), 512 + 160);
    }
    private static int[] core_sha1(int[] x, int len) {
        int size = (len >> 5);
        x = strechbinarray(x, size);
        x[len >> 5] |= 0x80 << (24 - len % 32);
        size = ((len + 64 >> 9) << 4) + 15;
        x = strechbinarray(x, size);
        x[((len + 64 >> 9) << 4) + 15] = len;
        int[] w = new int[80];
        int a = 1732584193;
        int b = -271733879;
        int c = -1732584194;
        int d = 271733878;
        int e = -1009589776;
        for (int i = 0; i < x.length; i += 16) {
            int olda = a;
            int oldb = b;
            int oldc = c;
            int oldd = d;
            int olde = e;
            for (int j = 0; j < 80; j++) {
                if (j < 16) {
                    w[j] = x[i + j];
                } else {
                    w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
                }
                int t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j)));
                e = d;
                d = c;
                c = rol(b, 30);
                b = a;
                a = t;
            }
            a = safe_add(a, olda);
            b = safe_add(b, oldb);
            c = safe_add(c, oldc);
            d = safe_add(d, oldd);
            e = safe_add(e, olde);
        }
        int[] retval = new int[5];
        retval[0] = a;
        retval[1] = b;
        retval[2] = c;
        retval[3] = d;
        retval[4] = e;
        return retval;
    }
    private static void dotest() {
        String key = "key";
        String data = "data";
        System.out.println("hex_sha1(" + data + ")=" + hex_sha1(data));
        System.out.println("b64_sha1(" + data + ")=" + b64_sha1(data));
        System.out.println("str_sha1(" + data + ")=" + str_sha1(data));
        System.out.println("hex_hmac_sha1(" + key + "," + data + ")=" + hex_hmac_sha1(key, data));
        System.out.println("b64_hmac_sha1(" + key + "," + data + ")=" + b64_hmac_sha1(key, data));
        System.out.println("str_hmac_sha1(" + key + "," + data + ")=" + str_hmac_sha1(key, data));
    }
    public static String hex_hmac_sha1(String key, String data) {
        return binb2hex(core_hmac_sha1(key, data));
    }
    private static int rol(int num, int cnt) {
        return (num << cnt) | (num >>> (32 - cnt));
    }
    private static int safe_add(int x, int y) {
        int lsw = (int) (x & 0xffff) + (int) (y & 0xffff);
        int msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        return (msw << 16) | (lsw & 0xffff);
    }
    private static int sha1_ft(int t, int b, int c, int d) {
        if (t < 20)
            return (b & c) | ((~b) & d);
        if (t < 40)
            return b ^ c ^ d;
        if (t < 60)
            return (b & c) | (b & d) | (c & d);
        return b ^ c ^ d;
    }
    private static int sha1_kt(int t) {
        return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514;
    }
    private static boolean sha1_vm_test() {
        return hexcase ? hex_sha1("abc").equals("a9993e364706816aba3e25717850c26c9cd0d89d") : hex_sha1("abc").equals(
                "a9993e364706816aba3e25717850c26c9cd0d89d");
    }
    public static String str_hmac_sha1(String key, String data) {
        return binb2str(core_hmac_sha1(key, data));
    }
    public static String str_sha1(String s) {
        s = (s == null) ? "" : s;
        return binb2str(core_sha1(str2binb(s), s.length() * chrsz));
    }
    private static int[] str2binb(String str) {
        str = (str == null) ? "" : str;
        int[] tmp = new int[str.length() * chrsz];
        int mask = (1 << chrsz) - 1;
        for (int i = 0; i < str.length() * chrsz; i += chrsz) {
            tmp[i >> 5] |= ((int) (str.charAt(i / chrsz)) & mask) << (24 - i % 32);
        }
        int len = 0;
        for (int i = 0; i < tmp.length && tmp[i] != 0; i++, len++)
            ;
        int[] bin = new int[len];
        for (int i = 0; i < len; i++) {
            bin[i] = tmp[i];
        }
        return bin;
    }
    private static int[] strechbinarray(int[] oldbin, int size) {
        int currlen = oldbin.length;
        if (currlen >= size + 1) {
            return oldbin;
        }
        int[] newbin = new int[size + 1];
        for (int i = 0; i < size; newbin[i] = 0, i++)
            ;
        for (int i = 0; i < currlen; i++) {
            newbin[i] = oldbin[i];
        }
        return newbin;
    }
    public static void main(String[] args) {
        System.out.println("admin的SHA1的值为:" + hex_sha1("123") + ",length=" + hex_sha1("admin").length());
    }
}

与 MD5SHA1 比较

代表

信息汇总

js加密 java解密_java加密解密_java md5加密后解密

安全散列算法

消息摘要的长度

128位

160位

识别原始消息需要

2的128次方运算

2的160次方运算

查找生成相同​​消息摘要的两条消息

需要2的64次方运算

需要 2 的 80 次方操作

安全

更差

中等的

速度

快速地

java md5加密后解密_java加密解密_js加密 java解密

慢的

可逆加密简介

对称加解密

非对称加解密

非对称意味着商家生成公钥和私钥

将公钥给用户,让用户加密,将加密后的密文发送给商家

商户正在使用私钥解密(有效防止盗窃)

对称加密:双方使用同一个密钥既可以加密也可以解密。 这种加密方式称为对称加密,也称为单密钥加密。

优点:速度快,对称加密通常在消息发送方需要加密大量数据时使用,算法开放,计算量小,加密速度快,加密效率高。

缺点:在传输数据之前,发送方和接收方必须商定一个秘钥,然后双方都可以保存秘钥。 其次,如果一方的密钥泄露,那么加密后的信息就不安全了。 另外,一对用户每次使用对称加密算法时,都需要使用一个别人不知道的唯一秘钥,这会造成接收方和发送方都拥有大量的密钥java加密解密,密钥管理将成为一个难题。双方的负担。

对称加密算法中常用的算法有:DES、AES等。

AES:密钥的长度可以是128、192和256位,即16字节、24字节和32字节

DES:密钥长度为64位,8字节。

非对称加密:一对密钥由一个公钥和一个私钥组成(可以使用多对密钥)。 私钥解密公钥加密的数据,公钥解密私钥加密的数据(私钥和公钥可以相互加密和解密)。

私钥只能由一方保管,不能泄露。 公钥可以提供给任何请求方。

js加密 java解密_java md5加密后解密_java加密解密

非对称加密算法中常用的算法有:

RSA、Elgamal、背包算法、Rabin、Diffie-Hellman、ECC(椭圆曲线密码术)。

使用最广泛的是RSA算法,Elgamal是另一种常用的非对称加密算法。

缺点:较慢

优点:安全

对称加解密AES


import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
public class AESUtil {
    public static final String AES = "AES";
    public static final String charset = "UTF-8"; // 编码格式
    public static final int keysizeAES = 128;
    private static AESUtil instance;
    private AESUtil() {
    }
    // 单例
    public static AESUtil getInstance() {
        if (instance == null) {
            synchronized (AESUtil.class) {
                if (instance == null) {
                    instance = new AESUtil();
                }
            }
        }
        return instance;
    }
    
    public String encode(String res, String key) {
        return keyGeneratorES(res, AES, key, keysizeAES, true);
    }
    
    public String decode(String res, String key) {
        return keyGeneratorES(res, AES, key, keysizeAES, false);
    }
    // 使用KeyGenerator双向加密,DES/AES,注意这里转化为字符串的时候是将2进制转为16进制格式的字符串,不是直接转,因为会出错
    private String keyGeneratorES(String res, String algorithm, String key, int keysize, boolean isEncode) {
        try {
            KeyGenerator kg = KeyGenerator.getInstance(algorithm);
            if (keysize == 0) {
                byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset);
                kg.init(new SecureRandom(keyBytes));
            } else if (key == null) {
                kg.init(keysize);
            } else {
                byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset);
                kg.init(keysize, new SecureRandom(keyBytes));
            }
            SecretKey sk = kg.generateKey();
            SecretKeySpec sks = new SecretKeySpec(sk.getEncoded(), algorithm);
            Cipher cipher = Cipher.getInstance(algorithm);
            if (isEncode) {
                cipher.init(Cipher.ENCRYPT_MODE, sks);
                byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset);
                return parseByte2HexStr(cipher.doFinal(resBytes));
            } else {
                cipher.init(Cipher.DECRYPT_MODE, sks);
                return new String(cipher.doFinal(parseHexStr2Byte(res)));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    // 将二进制转换成16进制
    private String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }
    // 将16进制转换为二进制
    private byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }
    public static void main(String[] args) {
        AESUtil instance = AESUtil.getInstance();
        //加密
        String jiami = instance.encode("hu867682752", "aaa");
        System.out.println(jiami);
        //解密
        String jiemi= instance.decode(jiami, "aaa");
        System.out.println(jiemi);
    }
}

DES

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
public class DESUtil {
    public static final String DES = "DES";
    public static final String charset = "UTF-8"; // 编码格式;默认null为GBK
    public static final int keysizeDES = 0;
    private static DESUtil instance;
    private DESUtil() {
    }
    // 单例
    public static DESUtil getInstance() {
        if (instance == null) {
            synchronized (DESUtil.class) {
                if (instance == null) {
                    instance = new DESUtil();
                }
            }
        }
        return instance;
    }
    
    public String encode(String res, String key) {
        return keyGeneratorES(res, DES, key, keysizeDES, true);
    }
    
    public String decode(String res, String key) {
        return keyGeneratorES(res, DES, key, keysizeDES, false);
    }
    // 使用KeyGenerator双向加密,DES/AES,注意这里转化为字符串的时候是将2进制转为16进制格式的字符串,不是直接转,因为会出错
    private String keyGeneratorES(String res, String algorithm, String key, int keysize, boolean isEncode) {
        try {
            KeyGenerator kg = KeyGenerator.getInstance(algorithm);
            if (keysize == 0) {
                byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset);
                kg.init(new SecureRandom(keyBytes));
            } else if (key == null) {
                kg.init(keysize);
            } else {
                byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset);
                kg.init(keysize, new SecureRandom(keyBytes));
            }
            SecretKey sk = kg.generateKey();
            SecretKeySpec sks = new SecretKeySpec(sk.getEncoded(), algorithm);
            Cipher cipher = Cipher.getInstance(algorithm);
            if (isEncode) {
                cipher.init(Cipher.ENCRYPT_MODE, sks);
                byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset);
                return parseByte2HexStr(cipher.doFinal(resBytes));
            } else {
                cipher.init(Cipher.DECRYPT_MODE, sks);
                return new String(cipher.doFinal(parseHexStr2Byte(res)));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    // 将二进制转换成16进制
    private String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }
    // 将16进制转换为二进制
    private byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }
    public static void main(String[] args) {
        DESUtil instance= DESUtil.getInstance();
          String jiami=  instance.encode("12345abc67","abc");
          System.out.println(jiami);
          String jiemi=instance.decode(jiami,"abc");
          System.out.println(jiemi);
    }
}

异或


public class XORUtil {
    private static XORUtil instance;
    private XORUtil() {
    }
    // 单例
    public static XORUtil getInstance() {
        if (instance == null) {
            synchronized (XORUtil.class) {
                if (instance == null) {
                    instance = new XORUtil();
                }
            }
        }
        return instance;
    }
    
    public int code(int res, String key) {
        return res ^ key.hashCode();
    }
    
    public String encode(String res, String key) {
        byte[] bs = res.getBytes();
        for (int i = 0; i < bs.length; i++) {
            bs[i] = (byte) ((bs[i]) ^ key.hashCode());
        }
        return parseByte2HexStr(bs);
    }
    
    public String decode(String res, String key) {
        byte[] bs = parseHexStr2Byte(res);
        for (int i = 0; i < bs.length; i++) {
            bs[i] = (byte) ((bs[i]) ^ key.hashCode());
        }
        return new String(bs);
    }
    // 将二进制转换成16进制
    private String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }
    // 将16进制转换为二进制
    private byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }
    public static void main(String[] args) {
        XORUtil  instance=  XORUtil.getInstance();
       String jiami= instance.encode("124ff","abc");
        System.out.println(jiami);
        String jiemi = instance.decode(jiami,"abc");
        System.out.println(jiemi);
//针对 纯数字 进行加密  和解密
        int num_jiami= instance.code(543,"abv");
        System.out.println(num_jiami);
        int num_jiemi= instance.code(num_jiami,"abv");
        System.out.println(num_jiemi);
    }
}

非对称 RSA 后端工具


import org.apache.commons.codec.binary.base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class RSAUtils {
//前端使用方法
//cript src="js/jsencrypt.js">cript>
//    function encryptRequest( text) {
//        var encrypt=new JSEncrypt();
//        encrypt.setPrivateKey("公秘钥");
			//生成密文
//        alert(encrypt.encrypt(text))
//    }
    
    private static Map<Integer, String> keyMap = new HashMap<>();
    
    public static void genKeyPair() {
        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        // 初始化密钥对生成器,密钥大小为96-1024位
        assert keyPairGen != null;
        keyPairGen.initialize(1024, new SecureRandom());
        // 生成一个密钥对,保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥
        String publicKeyString = new String(base64.encodebase64(publicKey.getEncoded()));
        // 得到私钥字符串
        String privateKeyString = new String(base64.encodebase64((privateKey.getEncoded())));
        // 将公钥和私钥保存到Map
        keyMap.put(0, publicKeyString);  //0表示公钥
        keyMap.put(1, privateKeyString);  //1表示私钥
    }
    
    public static String encrypt(String str, String publicKey) {
        //base64编码的公钥
        byte[] decoded = base64.decodebase64(publicKey);
        RSAPublicKey pubKey = null;
        String outStr = null;
        try {
            pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            outStr = base64.encodebase64String(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
        } catch (InvalidKeySpecException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException | NoSuchPaddingException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        //RSA加密
        return outStr;
    }
    
    public static String decrypt(String str, String privateKey) {
        //64位解码加密后的字符串
        byte[] inputByte = base64.decodebase64(str.getBytes(StandardCharsets.UTF_8));
        //base64编码的私钥
        byte[] decoded = base64.decodebase64(privateKey);
        RSAPrivateKey priKey = null;
        //RSA解密
        Cipher cipher = null;
        String outStr = null;
        try {
            priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            outStr = new String(cipher.doFinal(inputByte));
        } catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
            e.printStackTrace();
        }
        return outStr;
    }
    public static void main(String[] args) {
        //生成公钥和私钥
        genKeyPair();
        String  publicKey=keyMap.get(0);
        String  privateKey=keyMap.get(1);
        //加密字符串
        String message = "df723820";
        System.out.println("随机生成的公钥为:" + publicKey);
        System.out.println("随机生成的私钥为:" + privateKey);
        //加密 生成密文
        String messageEn = encrypt(message, publicKey);
        System.out.println("加密后的字符串为:" + messageEn);
        //解密
        String messageDe = decrypt(messageEn, privateKey);
        System.out.println("还原后的字符串为:" + messageDe);
    }
}

RSA 前端工具

jsencrypt.js

java md5加密后解密_js加密 java解密_java加密解密

关联:

提取码:1234

前端使用 RSA

使用步骤

后端生成公钥和私钥

前端使用公钥生成密文传给后端

后端使用私钥解析密文

当然,前端也可以生成公钥和私钥,但是一般把不安全的事情交给后端

公钥和私钥生成

前端

生成公钥和私钥并使用

    var encrypt=new JSEncrypt();
    var  publicKey = encrypt.getPublicKey();
    var privateKey = encrypt.getPrivateKey();
    alert("公钥\n"+publicKey)
    alert("私钥\n"+privateKey)
//前端使用方法
<script src="js/jsencrypt.js"></script>
	<script>
       function encryptRequest( text) {
        var encrypt=new JSEncrypt();
       encrypt.setPrivateKey("公秘钥");
			//生成密文
       alert(encrypt.encrypt(text))
    }
    
    </script>

后端

生成公钥和私钥并使用


 //生成公钥和私钥
   public static void main(String[] args) {
        //生成公钥和私钥
        genKeyPair();
        String  publicKey=keyMap.get(0);
        String  privateKey=keyMap.get(1);
        //加密字符串
        String message = "df723820";
        System.out.println("随机生成的公钥为:" + publicKey);
        System.out.println("随机生成的私钥为:" + privateKey);
        //利用公秘钥加密 生成密文   (这一步可以放到前端  )
        String messageEn = encrypt(message, publicKey);
        System.out.println("加密后的字符串为:" + messageEn);
        //解密  (传来的密文   利用私钥 解析出来 )
        String messageDe = decrypt(messageEn, privateKey);
        System.out.println("还原后的字符串为:" + messageDe);
    }

 
反对 0举报 0 收藏 0 打赏 0评论 0
 
更多>同类资讯
推荐图文
推荐资讯
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报
Powered By DESTOON