hashids的核心原理是映射,将原有字符映射为其它字符,且此映射是可逆的,网上有具体的原理和库,本文主要描述相关思路。
下文以伪代码对加解码描述思路。
// source = 输入数据
// secret = 编码的字符串,即初始数据部分
// 方法返回编码后的字符串
String encode(String source,String secret){
//1. 根据 secret 和固有的逻辑规则生成具体的映射规则M
//2. 使用规则M 对source 编码,得到的字符串坐返回
}
方式一,在简单模式下,可以生成一个固定内容的映射规则
将 A 映射为B ,将B映射为D,将C映射为A
输入 [ABC]
输出 [BDA]
方式二,整理好需要支持的字符内容集合,通过位置做内容映射
定义此方法仅仅支持ABCD四个字符的编码,则
原始字符为 [ABCD]; 用过洗牌算法将字符打乱为 [BCAD]
输入 [ABC]
根据原有字符在集合中的位置,到新集合中寻找对于字符做映射
输出 [BCA]
通过当前字符的位置,将之做内容映射
假设规则为 当前字符变换为 (编码字符集的索引位置 + 当前输入的索引位置 ) % 字符集长度 的对应原始字符串[ABCD]的索引的位置的字符。
定义此方法仅仅支持ABCD四个字符的集合, 则支持的字符集长度 = 4;原始字符串[ABCD]的索引的位置=[0,1,2,3]
编码逻辑:
输入字符集为 [AACC];
按照字符和位置依次处理:
输入字值,输入索引 -> (输入字值在输入字符集的索引值 + 字符在原始字符串中索引值) % 4 = 在原始字符串中的索引位置 = 编码后字符
这里可以理解为找到原始字符对应的编码集中的字符,并向环形后移动输入字符对应索引值得到的原始字符串中的字符。
A,索引0 -> 0 + 0 = 0 % 4 = 0 = A
A,索引1 -> 1 + 0 = 1 % 4 = 1 = B
C,索引2 -> 2 + 2 = 4 % 4 = 0 = A
C,索引3 -> 3 + 2 = 5 % 4 = 1 = B
输出 [BCAB]
解码逻辑, 由于原值的索引范围是 0 - 3, 未防止取余带来的数据变为负数,这里加上 4以保证正数索引,这里加上4是为了保证值为正数, 同样可以理解为是反向移动
编码后的值,编码串对应索引 -> (编码值对应原始字符串对应索引 - 编码串位置索引 + 4) % 4 = 原始值串[索引] = 原始值
A,索引0 -> 0 - 0 + 4 = 4 % 4 = A
B,索引1 -> 1 - 1 + 4 = 4 % 4 = A
A,索引0 -> 0 - 2 + 4 = 2 % 4 = C
B,索引1 -> 1 - 3 + 4 = 2 % 4 = C
输出 [AACC]
通过位置映射的优点是同一个字符在不同位置展示的值是不同的,如此增加了破解的难度;
对于某些需要高位或者低补充固定字符的内容来说,编码后肉眼可见的变得更加复杂。
将一段内容按照内容和位置,甚至其它自定义规则,按照顺序依次映射,则得到的结果将更难以还原,映射的规则的复杂度也大大提示。
但是,同一种规则的多次映射却没有必要,因为输入的参数和输出的结果在规则确定的情况下,是一定的,不论中间经过多少次变换。
假设按照内容映射
输入 a -> 映射为 b -> 将b 映射为 c -> 将c映射为 d ; 实质上等同于将 a 映射为 d; 因为中间的几个映射规则最终可以组合为一个;
只有调整输入内容,同时制定对应的规则才能形成更加复杂的规则;如同维度的增加,配上对应的处理规则的组合形成的复杂的多维多次函数。
上文例举的只是最简单的两个维度:内容,当前字符对应的位置。
上文提到可以每种输入可以看成一种维度,而这些维度都是在编码串中已知存在的,不具有很高的保密性;如果我们加入其它维度,将之混入映射的规则之中,则编码后的字符串还原的难度大增,此维度即为secret。通常我们使用一个静态内容,比如一个字符串来作为静态的secret,一般而言信息越多,规则越复杂(因为映射后对应内容规则的的重复映射次数越少,也就越具有随机性)。
示例
假设现在定义了一个 secret = 2431 ;
生成两种映射规则, 规则A为位置映射,规则B为内容映射,支持ABCD四种字符的映射;
step1:
生成原始字符串原本对应的索引 [A,B,C,D] = [0,1,2,3]
step2:
规则A,通过secret将原本对应的索引映射 [A,B,C,D] = [0 + 2,1 + 4,2 + 3,3 + 1] = [2,5,5,4];
取余以获取支持的字符串 [2 % 4,5 % 4,5 % 4,4 % 4] = [2,1,1,0];
通过setp1 逆向查找对应字符串 = [C,B,B,A]
step3:
规则B,通过secret 中每一个字符表示 ABCD 四种字符的交换规则,通过规则生成映射表,这里将位置2与4交换,将位置3与1交换;
映射表 = ABCD -> ADCB -> CDAB ;
[C,B,B,A] -> [A,D,D,C];
通过两种规则可以按照顺序来混合生成结果 [A,B,C,D] -> [A,D,D,C];
如果secret是动态生成的,比如根据时间来,不同时间自动根据规则、或者根据约定好的字符串来作为secret, 其复杂度可以进一步提升。但是考虑到解码要求,其可能附上解码需要的信息,导致编码后的内容增长。通常情况在高下可按照模块或者应用、用户来区分,而不是完全的动态生成规则。
这里提供了一种常见的字符串hashids编解码,仅供理解文章参考