19 crypto-js RC4 加密的具体处理

本文主要探讨了RC4加密算法在调用JavaHutool库和crypto-js库时出现的不同结果。通过测试用例展示了Java中的RC4加密过程,强调了加解密的对称性。同时,分析了两者的box序列初始化和异或操作。文章还提到了crypto-js中加密结果包含的固定盐值部分,并介绍了解密过程。最后,指出不同实现中随机因子的影响导致加密结果的差异。
摘要由CSDN通过智能技术生成

前言

这里主要是关于 RC4 加密的相关调研

之所以调研这个是因为之前存在一个问题, 调用 java 相关 api 进行 RC4 加密的结果 和调用 crypto-js 的结果不一样, 作为出发点开始

然后调用的 API 基于 hutool-5.4.0

然后 一部分基于 crypto-js 来进行分析 

测试用例

这里是一个简单的 java 的测试用例, 有使用 RC4 进行加解密

RC4 是一种对称加密, 算法也是对称的

package com.hx.test02;

import cn.hutool.crypto.symmetric.RC4;
import io.netty.buffer.ByteBufUtil;

public class Test21Rc4Encode {

    // Test21Rc4Encode
    public static void main(String[] args) {

        String key = "11111";
        RC4 crypto = new RC4(key);

        byte[] srcBytes = "xxx".getBytes();
        byte[] encodedBytes = crypto.crypt(srcBytes);
        byte[] doubleEncodedBytes = crypto.crypt(encodedBytes);

        System.out.println(ByteBufUtil.hexDump(srcBytes));
        System.out.println(ByteBufUtil.hexDump(encodedBytes));
        System.out.println(ByteBufUtil.hexDump(doubleEncodedBytes));
        int x = 0;

    }

}

RC4加密方式

传入的 msg 为原始字节序列  

依次遍历原始字节序列 sourceByte, 从 box序列 中获取一个影响参数 argByte 来进行 异或 计算得到 targetByte

然后 原始字节序列 所有的字节处理完成之后 即为加密处理之后的字节序列

加解密方式是一样的是利用了如下特性 ((sourceByte ^ argByte) ^ argByte) = sourceByte

在多次 crypt 计算的过程中, 初始化 box序列 相同, i, j 计算方式相同, 在多次 crypt 计算的过程中, 第 i 个字节, 对应的 argByte 是相同的

对于 RC4 算法, 其实 box 序列是怎么样的已经不重要了, 只是一些 argByte 的 影响因素 而已

稍微看一下 box 序列的初始化

虽然这个 box 序列不太重要, 但是可以稍微深入的了解一下它的实现

大致的实现就是 box 初始化为 256 长度的字节序列, 然后按照索引进行初始化

然后 下面的初始化就是 进行一个遍历 box 序列 然后进行一个和传入 key 序列相关的一个 数据交换操作

得到一个 “乱序” 的 box 序列

crypto-js 版本的 RC4

初始化 box 序列的地方, 当然 在不同的上下文可能 定义不一样, 这里是按照 上面的 RC4 加密的过程来进行判断的

测试用例如下

<html>
	<head>
		<title>test</title>
	</head>
	
	<script type="text/javascript" src="crypto-js.min.js" ></script>

	<script>
		// var md5 = CryptoJS.MD5("xxx");
		var key = "11111"
		var encrypted = CryptoJS.RC4.encrypt("xxx", key)
		console.log(encrypted.toString())
		
		var decrypted = CryptoJS.RC4.decrypt(encrypted.toString(), key).toString(CryptoJS.enc.Utf8)
		console.log(decrypted.toString())
		
	</script>
	
</html>

box 序列的初始化

这里也是 按照索引初始化, 然后按照遍历 box序列的 每一个字节 换换换

然后 循环每一个输入字节进行 异或操作

至于 pick 到的 n() 具体数字是什么不重要, 只要保证多次执行 输入序列的第i个字节 拿到的 argByte 是一样的即可

函数 n() 是 pick 四个字节的 argByte, 然后封装成 32 位的整数

this._i, this._j 保存的是上下文, 这里的算法细节 和 hutool-all 中的实现一致

可以发现的是当输入的 key 相同的情况下, 每次 上下文的 box 序列不相同, 这个又是怎么影响到的呢   

_doReset 中 box 序列有一个 e 的影响因素, 这个是外部传入的

这个 e 来自于根据 key 计算的一个 r

这里根据 key 生成 序列的时候, 传入的 i 为 null, 设置为 random() 影响到了 计算的结果 r 

从而继续向下传递 影响到了 _doReset 中的计算

crypto-js 版本的 RC4 的 ToString 的实现

转换的时候加了固定的 2 * 4 个字节, 添加了 t.words[表示 salt] 最后添加的才是 RC4 加密之后的结果

这里合计 2 * 4 + 2 * 4 + 3 = 19 字节, 然后进行 Base64 加密

t.words 来自于自于根据 key 计算的一个 r 的地方

同样和这个 随机因子有关系, 因此 他会变化

crypto-js 版本的 RC4解密 

将加密之后的文本 base64 解密, 然后校验前八个字节 "Salted__" 

然后 接着 八个字节作为 salt, 在 execute 中来作为影响 box 序列计算的 salt 

然后 后面的流程就和 加密一样了, 计算 box 序列, 然后 按字节异或 获取解密之后的文本 

另外还有一个 java版本 实现的 crypto-js 解密, 实现思路 貌似不同 

如何使用Java从CryptoJS解密加密的AES-256字符串?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值