⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 crypter.java

📁 MilyQQ是一个使用控制台的QQ客户端,基于LumaQQ的核心JQL包开发,只有一个可执行的jar包(MilyQQ.jar),携带方便,由于是Java程序,因此理论上应该可以运行于所有平台,不过基于
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
        }

        // 头部填充完了,这里开始填真正的明文了,也是满了8字节就加密,一直到明文读完
        int i = offset;
        while(len > 0) {
            if(pos < 8) {
                plain[pos++] = in[i++];
                len--;
            }
            if(pos == 8)
                encrypt8Bytes();
        }

        // 最后填上0,以保证是8字节的倍数
        padding = 1;
        while(padding <= 7) {
            if(pos < 8) {
                plain[pos++] = 0x0;
                padding++;
            }
            if(pos == 8)
                encrypt8Bytes();
        }

        return out;
    }

    /**
     * @param in
     *            需要加密的明文
     * @param inLen
     *            明文长度
     * @param k
     *            密钥
     * @return Message 密文
     */
    public byte[] encrypt(byte[] in, byte[] k) {
        return encrypt(in, 0, in.length, k);
    }

    /**
     * 加密一个8字节块
     *
     * @param in
     * 		明文字节数组
     * @return
     * 		密文字节数组
     */
    private byte[] encipher(byte[] in) {
        try {
            // 迭代次数,16次
            int loop = 0x10;
            // 得到明文和密钥的各个部分,注意java没有无符号类型,所以为了表示一个无符号的整数
            // 我们用了long,这个long的前32位是全0的,我们通过这种方式模拟无符号整数,后面用到的long也都是一样的
            // 而且为了保证前32位为0,需要和0xFFFFFFFF做一下位与
            long y = Util.getUnsignedInt(in, 0, 4);
            long z = Util.getUnsignedInt(in, 4, 4);
            long a = Util.getUnsignedInt(key, 0, 4);
            long b = Util.getUnsignedInt(key, 4, 4);
            long c = Util.getUnsignedInt(key, 8, 4);
            long d = Util.getUnsignedInt(key, 12, 4);
            // 这是算法的一些控制变量,为什么delta是0x9E3779B9呢?
            // 这个数是TEA算法的delta,实际是就是sqr(5)-1 * 2^31
            long sum = 0;
            long delta = 0x9E3779B9;
            delta &= 0xFFFFFFFFL;

            // 开始迭代了,乱七八糟的,我也看不懂,反正和DES之类的差不多,都是这样倒来倒去
            while (loop-- > 0) {
                sum += delta;
                sum &= 0xFFFFFFFFL;
                y += ((z << 4) + a) ^ (z + sum) ^ ((z >>> 5) + b);
                y &= 0xFFFFFFFFL;
                z += ((y << 4) + c) ^ (y + sum) ^ ((y >>> 5) + d);
                z &= 0xFFFFFFFFL;
            }

            // 最后,我们输出密文,因为我用的long,所以需要强制转换一下变成int
            ByteArrayOutputStream baos = new ByteArrayOutputStream(8);
            DataOutputStream dos = new DataOutputStream(baos);
            dos.writeInt((int)y);
            dos.writeInt((int)z);
            dos.close();
            return baos.toByteArray();
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * 解密从offset开始的8字节密文
     *
     * @param in
     * 		密文字节数组
     * @param offset
     * 		密文开始位置
     * @return
     * 		明文
     */
    private byte[] decipher(byte[] in, int offset) {
        try {
            // 迭代次数,16次
            int loop = 0x10;
            // 得到密文和密钥的各个部分,注意java没有无符号类型,所以为了表示一个无符号的整数
            // 我们用了long,这个long的前32位是全0的,我们通过这种方式模拟无符号整数,后面用到的long也都是一样的
            // 而且为了保证前32位为0,需要和0xFFFFFFFF做一下位与
            long y = Util.getUnsignedInt(in, offset, 4);
            long z = Util.getUnsignedInt(in, offset + 4, 4);
            long a = Util.getUnsignedInt(key, 0, 4);
            long b = Util.getUnsignedInt(key, 4, 4);
            long c = Util.getUnsignedInt(key, 8, 4);
            long d = Util.getUnsignedInt(key, 12, 4);
            // 算法的一些控制变量,为什么sum在这里也有数了呢,这个sum嘛就是和迭代次数有关系了
            // 因为delta是这么多,所以sum如果是这么多的话,迭代的时候减减减,减16次,最后
            // 得到什么? Yeah,得到0。反正这就是为了得到和加密时相反顺序的控制变量,这样
            // 才能解密呀~~
            long sum = 0xE3779B90;
            sum &= 0xFFFFFFFFL;
            long delta = 0x9E3779B9;
            delta &= 0xFFFFFFFFL;

            // 迭代开始了, #_#
            while(loop-- > 0) {
                z -= ((y << 4) + c) ^ (y + sum) ^ ((y >>> 5) + d);
                z &= 0xFFFFFFFFL;
                y -= ((z << 4) + a) ^ (z + sum) ^ ((z >>> 5) + b);
                y &= 0xFFFFFFFFL;
                sum -= delta;
                sum &= 0xFFFFFFFFL;
            }

            // 输出明文,注意要转成int
            ByteArrayOutputStream baos = new ByteArrayOutputStream(8);
            DataOutputStream dos = new DataOutputStream(baos);
            dos.writeInt((int)y);
            dos.writeInt((int)z);
            dos.close();
            return baos.toByteArray();
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * 解密
     *
     * @param in
     * 		密文
     * @return
     * 		明文
     */
    private byte[] decipher(byte[] in) {
        return decipher(in, 0);
    }

    /**
     * 加密8字节
     */
    private void encrypt8Bytes() {
        // 这部分完成我上面所说的 plain ^ preCrypt,注意这里判断了是不是第一个8字节块,如果是的话,那个prePlain就当作preCrypt用
        for(pos = 0; pos < 8; pos++) {
            if(header) plain[pos] ^= prePlain[pos];
            else plain[pos] ^= out[preCrypt + pos];
        }
        // 这个完成到了我上面说的 f(plain ^ preCrypt)
        byte[] crypted = encipher(plain);
        // 这个没什么,就是拷贝一下,java不像c,所以我只好这么干,c就不用这一步了
        System.arraycopy(crypted, 0, out, crypt, 8);

        // 这个就是完成到了 f(plain ^ preCrypt) ^ prePlain,ok,完成了,下面拷贝一下就行了
        for(pos = 0; pos < 8; pos++)
            out[crypt + pos] ^= prePlain[pos];
        System.arraycopy(plain, 0, prePlain, 0, 8);

        // 完成了加密,现在是调整crypt,preCrypt等等东西的时候了
        preCrypt = crypt;
        crypt += 8;
        pos = 0;
        header = false;
    }

    /**
     * 解密8个字节
     *
     * @param in
     * 		密文字节数组
     * @param offset
     * 		从何处开始解密
     * @param len
     * 		密文的长度
     * @return
     * 		true表示解密成功
     */
    private boolean decrypt8Bytes(byte[] in , int offset, int len) {
        // 这里第一步就是判断后面还有没有数据,没有就返回,如果有,就执行 crypt ^ prePlain
        for(pos = 0; pos < 8; pos++) {
            if(contextStart + pos >= len)
                return true;
            prePlain[pos] ^= in[offset + crypt + pos];
        }

        // 好,这里执行到了 d(crypt ^ prePlain)
        prePlain = decipher(prePlain);
        if(prePlain == null)
        	return false;

        // 解密完成,wait,没完成哦,最后一步没做哦?
        // 这里最后一步放到decrypt里面去做了,因为解密的步骤毕竟还是不太一样嘛
        // 调整这些变量的值先
        contextStart += 8;
        crypt += 8;
        pos = 0;
        return true;
    }

    /**
     * 这是个随机因子产生器,用来填充头部的,如果为了调试,可以用一个固定值
     * 随机因子可以使相同的明文每次加密出来的密文都不一样
     *
     * @return
     * 		随机因子
     */
    private int rand() {
        return random.nextInt();
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -