序列密码(RC4)

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: RC4是 Ron Rivest 在1987年为RSA数据安全公司开发的可变密钥长度的序列密码。

序列密码(RC4)


image.png

                                                      RC4

发展历史

RC4是 Ron Rivest 在1987年为RSA数据安全公司开发的可变密钥长度的序列密码。

image.gifRC4加密密钥生成


加密/解密流程

  1. 初始化s_box
for i from 0 to 255
    S[i] := i
endfor
j := 0
for i from 0 to 255
    j := (j + S[i] + key[i mod keyLength]) mod 256
    swap values of S[i] and S[j]
endfor
  1. 生成随机的密钥流
i := 0
j := 0
while GeneratingOutput:
    i := (i + 1) mod 256
    j := (j + S[i]) mod 256
    swap values of S[i] and S[j]
    K := S[(S[i] + S[j]) mod 256]
    output K
endwhile
  1. 加密/解密算法

将明文当中的每一个字节和生成的密钥流进行异或, 即可得到加密之后的字节流。

对于RC4而言,加密过程真的很简洁,用代码实现起来也不是太复杂,因为我正在学习rust, 因此贴一个rust版的代码实现 哈哈 学以致用了。


代码实现

pub struct RC4 {
    i: u8,
    j: u8,
    s_box: [u8; 256],
}
impl RC4 {
    pub fn init(key: &[u8]) -> RC4 {
        let mut rc4 = RC4 { i: 0, j: 0, s_box: [0; 256] };
        for (i, x) in rc4.s_box.iter_mut().enumerate() {
            *x = i as u8;
        }
        let mut j = 0u8;
        for i in 0..256 {
            j = j.wrapping_add(rc4.s_box[i]).wrapping_add(key[i % key.len()]);
            rc4.s_box.swap(i, j as usize);
        }
        return rc4;
    }
    fn next(&mut self) -> u8 {
        self.i = self.i.wrapping_add(1);
        self.j = self.j.wrapping_add(self.s_box[self.i as usize]);
        self.s_box.swap(self.i as usize, self.j as usize);
        self.s_box[(self.s_box[self.i as usize].wrapping_add(self.s_box[self.j as usize])) as usize]
    }
    fn crypt(&mut self, input: &[u8], output: &mut [u8]) {
        for (i, j) in input.iter().zip(output.iter_mut()) {
            *j = *i ^ self.next();
        }
    }
}
#[cfg(test)]
mod test {
    use crate::rc4::RC4;
    use std::iter::repeat;
    #[test]
    fn test() {
        let mut rc4 = RC4::init("key".as_bytes());
        let plaintext = "plaintext";
        let mut result: Vec<u8> = repeat(0).take(plaintext.len()).collect();
        rc4.crypt(plaintext.as_bytes(), &mut result);
        println!("{:?}", result);
    }
}


RC4的变种

对于RC4也出现了不少的变种算法,下面给出几个变种算法以及对应的实现, 具体的算法描述不展开了,有感兴趣的可以参考一下文章后面的参考资料。


RC4A

pub struct RC4A {
    i: u8,
    j1: u8,
    j2: u8,
    s1: [u8; 256],
    s2: [u8; 256],
}
impl RC4A {
    pub fn init(key: &[u8]) -> RC4A {
        let mut rc4a = RC4A { i: 0, j1: 0, j2: 0, s1: [0; 256], s2: [0; 256] };
        // init s1
        for (i, x) in rc4a.s1.iter_mut().enumerate() {
            *x = i as u8;
        }
        let mut j = 0u8;
        for i in 0..256 {
            j = j.wrapping_add(rc4a.s1[i]).wrapping_add(key[i % key.len()]);
            rc4a.s1.swap(i, j as usize);
        }
        // init s2
        for (i, x) in rc4a.s2.iter_mut().enumerate() {
            *x = i as u8;
        }
        let mut j = 0u8;
        for i in 0..256 {
            j = j.wrapping_add(rc4a.s2[i]).wrapping_add(key[i % key.len()]);
            rc4a.s2.swap(i, j as usize);
        }
        return rc4a;
    }
    fn next1(&mut self) -> u8 {
        self.i = self.i.wrapping_add(1);
        self.j1 = self.j1.wrapping_add(self.s1[self.i as usize]);
        self.s1.swap(self.i as usize, self.j1 as usize);
        self.s2[(self.s1[self.i as usize].wrapping_add(self.s1[self.j1 as usize])) as usize]
    }
    fn next2(&mut self) -> u8 {
        self.i = self.i.wrapping_add(1);
        self.j2 = self.j2.wrapping_add(self.s2[self.i as usize]);
        self.s2.swap(self.i as usize, self.j2 as usize);
        self.s1[(self.s2[self.i as usize].wrapping_add(self.s2[self.j2 as usize])) as usize]
    }
    fn crypt(&mut self, input: &[u8], output: &mut [u8]) {
        for (i, j) in input.iter().zip(output.iter_mut()) {
            *j = *i ^ self.next1();
        }
        for (i, j) in input.iter().zip(output.iter_mut()) {
            *j = *i ^ self.next2();
        }
    }
}
#[cfg(test)]
mod test {
    use crate::rc4a::RC4A;
    use std::iter::repeat;
    #[test]
    fn test() {
        let mut rc4a = RC4A::init("Key".as_bytes());
        let plaintext = "plaintext";
        let mut result: Vec<u8> = repeat(0).take(plaintext.len()).collect();
        rc4a.crypt(plaintext.as_bytes(), &mut result);
        println!("{:?}", result);
        let mut rc4a = RC4A::init("Key".as_bytes());
        let mut output: Vec<u8> = repeat(0).take(plaintext.len()).collect();
        rc4a.crypt(&result, &mut output);
        println!("{:?}", output);
    }
}


VMPC

pub struct VMPC {
    s: u8,
    p: [u8; 256],
}
impl VMPC {
    pub fn init(key: &[u8], iv: &[u8]) -> VMPC {
        let mut vmpc = VMPC { s: 0, p: [0; 256] };
        for (i, x) in vmpc.p.iter_mut().enumerate() {
            *x = i as u8;
        }
        for i in 0..768 {
            vmpc.s = vmpc.p[(vmpc.s.wrapping_add(vmpc.p[i % 256]).wrapping_add(key[i % key.len()])) as usize];
            vmpc.p.swap(i % 256, vmpc.s as usize);
        }
        for i in 0..768 {
            vmpc.s = vmpc.p[(vmpc.s.wrapping_add(vmpc.p[i % 256]).wrapping_add(iv[i % key.len()])) as usize];
            vmpc.p.swap(i % 256, vmpc.s as usize);
        }
        return vmpc;
    }
    fn crypt(&mut self, input: &[u8], output: &mut [u8]) {
        let mut  n = 0u8;
        for i in 0..input.len() {
            self.s = self.p[(self.s.wrapping_add(self.p[n as usize])) as usize];
            output[i] = input[i] ^ self.p[(self.p[(self.p[self.s as usize].wrapping_add(1)) as usize]) as usize];
            self.p.swap(n as usize, self.s as usize);
            n = n.wrapping_add(1);
        }
        return;
    }
}
#[cfg(test)]
mod test {
    use crate::vmpc::VMPC;
    use std::iter::repeat;
    #[test]
    fn test() {
        let mut vmpc = VMPC::init("Key".as_bytes(), "iv00".as_bytes());
        let plaintext = "plaintext";
        let mut result: Vec<u8> = repeat(0).take(plaintext.len()).collect();
        vmpc.crypt(plaintext.as_bytes(), &mut result);
        println!("{:?}", result);
        let mut vmpc = VMPC::init("Key".as_bytes(), "iv00".as_bytes());
        let mut output: Vec<u8> = repeat(0).take(plaintext.len()).collect();
        vmpc.crypt(&result, &mut output);
        println!("{:?}", output);
    }
}


Spritz

pub struct Spritz {
    i: u8,
    j: u8,
    k: u8,
    z: u8,
    a: u8,
    w: u8,
    s: [u8; 256],
}
impl Spritz {
    pub fn init() -> Spritz {
        // INITIALIZE_STATE
        let mut spritz = Spritz { i: 0, j: 0, k: 0, z: 0, a: 0, w: 1, s: [0; 256] };
        for (i, x) in spritz.s.iter_mut().enumerate() {
            *x = i as u8;
        }
        return spritz;
    }
    pub fn absorb(&mut self, buff: &[u8]) {
        for byte in buff {
            self.absorb_byte(&byte)
        }
    }
    fn absorb_byte(&mut self, b: &u8) {
        // absorb low
        self.absorb_nibble(b & 0xf);
        // absorb high
        self.absorb_nibble(b >> 4);
    }
    fn absorb_nibble(&mut self, x: u8) {
        if self.a >= 128 {
            self.shuffle()
        }
        // swap(S[s], S[N/2 + x])
        self.s.swap(self.a as usize, (128 + x) as usize);
        self.a += 1;
    }
    fn absorb_stop(&mut self) {
        if self.a >= 128 {
            self.shuffle()
        }
        self.a += 1;
    }
    fn shuffle(&mut self) {
        self.whip();
        self.crush();
        self.whip();
        self.crush();
        self.whip();
        self.a = 0;
    }
    fn whip(&mut self) {
        for _ in 0..512 {
            self.update();
        }
        self.w = self.w.wrapping_add(2);
    }
    fn crush(&mut self) {
        for v in 0..128 {
            let mut a = self.s[v];
            let mut b = self.s[255 - v];
            if a > b {
                self.s.swap(v as usize, (255 - v) as usize);
            }
        }
    }
    fn drip(&mut self) -> u8 {
        if self.a > 0 {
            self.shuffle()
        }
        self.update();
        return self.output();
    }
    fn update(&mut self) {
        // i = i + w
        self.i = self.i.wrapping_add(self.w);
        // j = k + S[j + S[i]]
        self.j = self.k.wrapping_add(self.s[self.j.wrapping_add(self.s[self.i as usize]) as usize]);
        // k = i + k + S[j]
        self.k = self.i.wrapping_add(self.k).wrapping_add(self.s[self.j as usize]);
        // swap S[i], S[j]
        self.s.swap(self.i as usize, self.j as usize);
    }
    fn output(&mut self) -> u8 {
        // z = S[j + S[i + S[z + k]]]
        self.z = self.s[self.j.wrapping_add(self.s[self.i.wrapping_add(self.s[self.z.wrapping_add(self.k) as usize]) as usize]) as usize];
        return self.z;
    }
    fn crypt(&mut self, input: &[u8], output: &mut [u8]) {
        if self.a > 0 {
            self.shuffle()
        }
        for (i, j) in input.iter().zip(output.iter_mut()) {
            *j = *i ^ self.drip();
        }
    }
}
#[cfg(test)]
mod test {
    use crate::spritz::Spritz;
    use std::iter::repeat;
    #[test]
    fn test() {
        let mut spritz = Spritz::init();
        spritz.absorb("Key".as_bytes());
        let mut result: Vec<u8> = repeat(0).take("plaintext".len()).collect();
        spritz.crypt("plaintext".as_bytes(), &mut result);
        println!("{:?}", result);
        let mut spritz = Spritz::init();
        let mut output: Vec<u8> = repeat(0).take("plaintext".len()).collect();
        spritz.absorb("Key".as_bytes());
        spritz.crypt(&result, &mut output);
        println!("{:?}", output);
    }
}

代码仅供参考学习使用(简单的实现),未经过严格测试,请不要直接用于生产用途,避免造成损失。

相关文章
|
5月前
|
Linux
Linux 目录 rc0.d rc1.d rc2.d rc3.d rc4.d rc5.d rc6.d 是干什么的?
【6月更文挑战第10天】Linux 目录 rc0.d rc1.d rc2.d rc3.d rc4.d rc5.d rc6.d 是干什么的?
184 3
|
6月前
|
Linux
Linux 目录 rc0.d rc1.d rc2.d rc3.d rc4.d rc5.d rc6.d 是干什么的
【5月更文挑战第17天】Linux 目录 rc0.d rc1.d rc2.d rc3.d rc4.d rc5.d rc6.d 是干什么的
206 1
|
Perl
update-rc.d 命令
update-rc.d 命令
648 0
armbian下使用/etc/rc.local实现开机启动自己的多个程序
刚刚折腾完的事情,就是通过/etc/rc.local中增加我的程序启动命令。这里遇到一个问题,发现只能启动一个,然后百度查询,有人提到这是因为程序运行之后占用了命令行,不返回,所以不再继续执行,于是写了程序分成子进程的方案,虽然代码已经给出,但是对我来讲还是太难了点,继续寻找其他方案,还真找到了,只需要增加一个 &符号分割就可以再执行另外一个程序的启动命令了。
1754 0
|
Linux
16.7 Linux /etc/rc.d/rc.local配置文件
在 /etc/rc[06].d/ 目录中的程序启动之后,系统的启动就已经完成。不过,我们总有一些程序是需要在系统启动之后随着系统一起启动的。这时我们并不需要自己把需要启动的服务链接到 /etc/rc3.d/ 目录中,因为系统给我们准备了 /etc/rc.d/rc.local 配置文件。
267 0
16.7 Linux /etc/rc.d/rc.local配置文件
|
UED
什么是RC版本?
常见的 RC 版本,全称是 Release Candidate。其中 Release 是发行、发布的意思。Candidate 是候选人的意思,用在软件或者操作系统上就是候选版本。因此 Release Candidate 就是发行候选版本。
696 0